在多个进程同时执行在执行通信时,由写部分必须有先后,为了保证按照指定的要求进行执行,这个时候就引入了生产者消费者模型。
何以为生产者、消费者?
生产者:就是制作一个可以通信的标志位,对标志位进行++操作,从而生产资源,也可理解为(释放资源,进V操作)。
if(完成某种操作)
{
对信号量++;进行生产
}
消费者:顾名思义就是当生产者生产过后,其标志位发生变化,然后操作之后进行消费(申请资源,P操作 )。
while(1)
{
if(已经生产)
{
标志位--;
break;
}
}
其实信号灯的操作就是这样,消费者随时去查看生产者生产没有,生产力消费者就消费。
下面则是使用信号灯所需要使用到的函数:
1、创建、打开信号灯集 int semget()
//计算key值
key_t ftok(const char *pathname, int proj_id);
参数1:const char *pathname:文件路径
参数2:int proj_id:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg)
参数1:指定信号灯的key值
参数2:信号灯集中含有多少个信号量
参数3:访问权限 通常是 0666 | IPC_CREAT
返回值:
成功:信号灯的id
失败:-1
2、信号灯的操作(V操作、P操作,也可以叫做+、-操作) int semop()
int semop(int semid, struct sembuf *sops, size_t nsops)
参数1:要操作的信号灯id
参数2:struct sembuf *sops结构体(要操作信号灯的结构体地址)
struct sembuf //信号量的值大于0
{
unsigned short sem_num; 要操作信号量编号
short sem_op; 0:等到信号量为0 <0:信号量减 >0:信号量加
short sem_flg; IPC_NOWAIT:非阻塞等待,直接结束 0:阻塞等待,直到信号量操作
}
参数3:要操作信号灯个数
3、控制信号灯集 int semctl()
int semctl(int semid, int semnum, int cmd,....);
参数1:要控制的信号灯集
参数2:要控制的信号灯编号
参数3:控制命令
IPC_STAT:获取信号灯集状态
IPC_SET:设置信号灯状态
IPC_RMID:删除信号灯集(2、4参数无用)
GETVAL:获取指定信号量的值
SETVAL:设置指定信号量的值
参数4:可有可无 NULL 有就是共用体类型
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) */
};
返回值:
成功:cmd == GETVAL 获取到的信号量的值
失败:-1
理解了上面几个函数之后,可能对上手还是有点困难,那在写一个示例进行阅读就OK了。
关于信号灯写操作
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
int main()
{
key_t key = ftok("home/ubuntu",10);
int shmid = shmget(key,1024,0666 | IPC_CREAT); //创建一个共享内存
if (shmid <0)
{
perror("create errorr\");
return -1;
}
key = ftok("home/ubuntu",20);
int semid = semget(key,1,0666|IPC_CREA)//创建一个信号灯集,信号量就1个
char *p = shmat(shmid,NULL,0);//将共享内存映射到进程的地址中,权限读写
struct sembuf sem;
semctl(sembuf,0,SETVAL,0);
while(1)
{
sem.sem_num = 0;
sem.sem_op = 0;
sem.sem_flg = 0;
semop(semid,&sem,1);//等待信号灯值变为0
fgets(p,1024,stdin);//把数据写入到共享内存
//生产者 信号量++
sem.sem_num = 0;
sem.sem_op = 1;
sem.sem_flg = 0;
semop(semid,&sem,1);
if(strcmp(p,"quit\n")==0)
{
break;
}
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
semctl(semid,0,IPC_RMID);
return 0;
}
信号灯读操作,和写差距不大
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
int main()
{
key_t key = ftok("/home/ubuntu",10);//计算出key值,应该和创建的进程使用的key一致
int shmid = shmget(key,1024,0666 | IPC_CREAT);//创建 打开共享内存,得到标识
if(shmid < 0)
{
perror("shm get error");
return -1;
}
key = ftok("/home/ubuntu",20);//计算出key值
int semid = semget(key,1,0666 | IPC_CREAT);
char * p = shmat(shmid,NULL,0);
struct sembuf sem;
sem.sem_num = 0;
sem.sem_op = -1;
sem.sem_flg = 0;
while(1)
{
//消费者操作 --
semop(semid,&sem,1);
if(strcmp(p,"quit\n") == 0)
{
break;
}
printf("%s",p);
sleep(1);
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
semctl(semid,0,IPC_RMID);
return 0;
}
在进程间通信的时候,需要将读程序和写程序都要进行运行才可以,否则不会进行工作。