目录
2. 将共享内存和信号灯集完成两个进程间通信程序重新实现一下
如果两个指针同时指向一片地址,如果一个指针释放掉,另一个指针怎么知道已经释放了?
1.使用三个进程来完成输出 ABCABCABCABCABC
test1.c
#include <head.h>
#include "sem.h"
int main(int argc, const char *argv[])
{
//创建一个信号灯集
int semid = create_sem(3);
if(semid ==-1){
perror("create_sem error");
return -1;
}
//定义两个进程号
pid_t pid1 =-1;
pid_t pid2 =-1;
int n=5;
//创建进程
pid1=fork();
if(pid1>0){
pid2=fork();
if(pid2>0){
//父进程
while(n--){
P(semid,2); //申请信号灯2资源
printf("A");
fflush(stdout);
V(semid,0); //释放信号灯0资源
}
wait(NULL); //回收子进程资源
wait(NULL); //回收子进程资源
}else if(pid2==0){
//子进程2
while(n--){
P(semid,0); //申请信号灯0资源
printf("B");
fflush(stdout);
V(semid,1); //释放信号灯1资源
}
exit(EXIT_SUCCESS); //退出子进程2
}else{
perror("fork2 error");
return -1;
}
}else if(pid1==0){
//子进程1
while(n--){
P(semid,1); //申请信号灯1资源
printf("C");
fflush(stdout);
V(semid,2); //释放信号灯2资源
}
exit(EXIT_SUCCESS); //退出子进程1
}else{
perror("fork1 error");
return -1;
}
puts("");
//删除信号灯集
del_sem(semid);
return 0;
}
sem.h
#ifndef __SEM_H__
#define __SEM_H__
//信号灯集的申请,初始化信号灯,并返回信号灯集的id
int create_sem(int semcount);
//申请信号灯资源操作 P操作
int P(int semid,int semno);
//释放信号灯资源操作 V操作
int V(int semid,int semno);
//信号灯集的删除
int del_sem(int semid);
#endif
sem.c
#include <head.h>
//定义共用体类型
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
//初始化函数
int init_sem(int semid, int semno)
{
int val = -1;
printf("请输入标号为%d的灯的初始值:", semno);
scanf("%d", &val);
getchar();
//对当前灯进行赋初始值
//定义一个共用体变量
union semun us;
us.val = val; //要赋的值
if(semctl(semid, semno, SETVAL, us) == -1)
{
perror("set val error");
return -1;
}
//成功返回0
return 0;
}
//信号灯集的申请,初始化信号灯,并返回信号灯集的id
int create_sem(int semcount){
//1.创建key值
key_t key = ftok("/",'y');
if(key==-1){
perror("ftok error");
return -1;
}
//2.通过key值创建一个信号灯集
int semid =semget(key,semcount,IPC_CREAT|IPC_EXCL|0664);
if(semid==-1){
if(errno==EEXIST){
//说明信号灯集已经存在,无需创建直接打开即可
semid = semget(key,semcount,IPC_CREAT);
return semid;
}
perror("semget error");
return -1;
}
//3、给信号灯集中的信号灯进行初始化操作
for(int i=0; i<semcount; i++)
{
init_sem(semid, i); //初始化标号为i的灯value值
}
//4、返回值信号灯集的id
return semid;
}
//申请信号灯资源操作 P操作
int P(int semid,int semno){
//定义一个操作的结构体变量
struct sembuf buf;
buf.sem_num = semno; //要操作的灯的编号
buf.sem_op = -1; //表示申请资源操作
buf.sem_flg = 0; //如果没有资源,则阻塞等待
//调用semop函数完成P操作
if(semop(semid, &buf, 1) == -1)
{
perror("P error");
return -1;
}
return 0; //成功返回0
}
//释放信号灯资源操作 V操作
int V(int semid,int semno){
//定义一个操作的结构体变量
struct sembuf buf;
buf.sem_num = semno; //要操作的灯的编号
buf.sem_op = 1; //表示释放资源操作
buf.sem_flg = 0; //如果没有资源,则阻塞等待
//调用semop函数完成V操作
if(semop(semid, &buf, 1) == -1)
{
perror("P error");
return -1;
}
return 0; //成功返回0
}
//信号灯集的删除
int del_sem(int semid){
//调用semc函数完成信号灯集的删除
if(semctl(semid, 0, IPC_RMID, 0) == -1)
{
perror("delete error");
return -1;
}
return 0;
}
2. 将共享内存和信号灯集完成两个进程间通信程序重新实现一下
shmsnd.c
#include <head.h>
#include "sem.h"
#define PAGE_SIZE 4096
int main(int argc, const char *argv[])
{
//11.创建信号灯集
int semid =create_sem(2);
if(semid==-1){
perror("create_sem error");
return -1;
}
//1.创建一个key值
key_t key= ftok("/",'m');
if(key==-1){
perror("ftok error") ;
return -1;
}
printf("key =%#x\n",key);
//2.通过key值创建共享内存段
int shmid= shmget(key,PAGE_SIZE,IPC_CREAT|0664);
if(shmid==-1){
perror("shmget error");
return -1;
}
printf("shmid = %d\n",shmid);
//3.将共享内存段映射到内存空间
char *addr = shmat(shmid,NULL,0);
if(addr==(void*)-1){
perror("shmat error");
return -1;
}
printf("addr=%p\n",addr);
//4.使用共享内存段
while(1){
//22.P操作
P(semid,0); //申请0号灯的资源
printf("请输入>>>>");
fgets(addr,PAGE_SIZE,stdin);
addr[strlen(addr)-1]=0;
//33.V操作
V(semid,1); //释放1号灯的资源
//判断退出条件
if(strcmp(addr,"quit")==0){
break;
}
}
//5.取消映射
if(shmdt(addr)==-1){
perror("shmdt error");
return -1;
}
//6.删除共享内存
return 0;
}
shmrcv.c
#include <head.h>
#include "sem.h"
#define PAGE_SIZE 4096
int main(int argc, const char *argv[])
{
//11.创建信号灯集
int semid =create_sem(2);
if(semid==-1){
perror("create_sem error");
return -1;
}
//1.创建一个key值
key_t key= ftok("/",'m');
if(key==-1){
perror("ftok error");
return -1;
}
printf("key =%#x\n",key);
//2.通过key值创建共享内存段
int shmid= shmget(key,PAGE_SIZE,IPC_CREAT|0664);
if(shmid==-1){
perror("shmget error");
return -1;
}
printf("shmid = %d\n",shmid);
//3.将共享内存段映射到内存空间
char *addr = shmat(shmid,NULL,0);
if(addr==(void*)-1){
perror("shmat error");
return -1;
}
printf("addr=%p\n",addr);
//4.使用共享内存段
while(1){
//22.P操作
P(semid,1); //申请1号灯的资源
printf("共享内存中的值是:%s\n",addr);
//33.V操作
V(semid,0); //释放0号灯的资源
//判断退出条件
if(strcmp(addr,"quit")==0){
break;
}
}
//5.取消映射
if(shmdt(addr)==-1){
perror("shmdt error");
return -1;
}
//44.删除信号灯集
del_sem(semid);
//6.删除共享内存
if(shmctl(shmid,IPC_RMID,NULL)==-1){
perror("shmctl error");
return -1;
}
return 0;
}
思维导图:
左值和右值:
左值表示的是可以被识别和存储地址的表达式,它可以出现在赋值语句的左边。左值可以出现在赋值操作的目标位置。
右值表示的是无法识别和存储地址的表达式,它只能出现在赋值语句的右边。通常,右值在表达式计算后会生成一个具体的数值或结果。