linux中的进程通信-信号量和有名管道
1、为了实现一种通用性对信号量函数进行封装(头文件sys/sem.h)
(1)创建一个或者打开一个信号量集
void sem_get(int key,int val[],int len)//信号集中信号个数由len确定
{
semid=semget((key_t)key,len,0666);
if(semid==-1)
{
semid=semget((key_t)key,len,0666|IPC_CREAT);//确保获取到信号量集
assert(semid!=-1);
union senun v;
int i=0;
for(;i<len;++i)
{
v.val=val[len];
semctl(semid,i,SETVAL,v);
}
}
}
(2)p、v操作
void sem_p(int semnum) //资源的使用信号(-1)传参为第几个信号量 (从0开始)
{
struct sembuf op;
op.sem_num=semnum;
op.sem_op=-1;
op.sem_flg=SEM_UNDO;
semop(semid,&op,1);
}
void sem_v(int semnum)//资源的释放信号(+1)
{
struct sembuf op;
op.sem_num=semnum;
op.sem_op=1;
op.sem_flg=SEM_UNDO;
semop(semid,&op,1);
}
4、信号的删除
void sem_del()
{
semctl(semid,0,IPC_RMID,NULL);
}
2、对于两个进程之间的通信 用一个例子来实现:A、B两个进程,A进程负责接收用户输入,B进程负责执行和输出;当用户在A进程中输入”ok”时,B进程输出“我准备好了”,当用户在A进程中输入“走你”时,B进程开始打印100以内所有素数;
(1)方法一:只用信号量控制,用两个信号量sem1和sem2分别控制“ok”和“走你”;
1>在A进程中:
void main()
{
int val=2;
sem_get((key_t)1234,&val,2);
printf("进程A开始:\n");
while(1)
{
printf("please input:\n");
char buff[128]={0};
fgets(buff,127,stdin);
buff[strlen(buff)-1]=0;
if(strncmp(buff,"ok",2)==0)
{
sem_v(0);//信号集中的信息从0下标开始 对第一个信号量进行v操作
}
else if(strncmp(buff,"走你",4)==0)
{
sem_v(1);//对第二个信号量进行v操作
}
}
}
2>在B进程中
void main()
{
int val=2;
sem_get((key_t)1234,&val,2);
printf("B进程开始:\n");
while(1)
{
sem_p(0);//对第一个信号量进行p操作
printf("我准备好了\n");
sem_p(1);//对第二个信号量进行p操作
printf("我开始计算100以内所有素数\n");
int i=1;
for(;i<100;++i)
{
int j=2;
for(;j<i;++j)
{
if(i%j==0)break;
}
if(i==j || i==1)
printf("%d ",i);
}
printf("\n");
}
}
(2)方法二:同时用到了信号量和管道控制:首先设置资源为0,当A进程接收到“ok”时,使用v操作,B进程退出阻塞,输出我准备好了同时进行p操作,当A进程接收到“走你”时,用管道发送“begin”到B进程,B进程开始计算(当然用两个管道阻塞也可以实现)
1>A进程中:
void main()
{
int val=1;
sem_get((key_t)1234,&val,1);//A、B进程控制同一个信号量
printf("A进程开始:\n");
while(1)
{
printf("please input:\n");
char buff[128]={0};
fgets(buff,128,stdin);
buff[strlen(buff)-1]=0;
if(strncmp(buff,"ok",2)==0)
{
sem_v(0);
}
else if(strncmp(buff,"走你",4)==0)
{
int fd=open("FIFD",O_WRONLY);
assert(fd!=-1);
write(fd,"begin",5);
}
}
}
2>B进程中
void main()
{
int val=1;
sem_get((key_t)1234,&val,1);
printf("B进程开始:\n");
while(1)
{
sem_p(0);//资源为0 阻塞等待A进程中的v操作的执行
printf("我准备好了\n");
int fd=open("FIFD",O_RDONLY);//管道阻塞
assert(fd!=-1);
char buff[128]={0};
read(fd,buff,127);
if(strncmp(buff,"begin",5)==0)//判断从管道中读取的数据是否为“begin”
{
printf("我开始计算100以内素数\n");
//省略计算打印过程 参考方法一
}
}
}