//头文件
#include
#include
#include
int semget(key_t key,int nsems,int flag);创建一个信号量集或访问一个已存在的信号量集。返回值:成功时,返回一个称为信号量标识符的整数,semop和semctl会使用它。出错返回-1.int semop(int semid,struct sembuf *sops,size_t num_sops);用于改变信号量对象中各个信号量的状态。成功返回0,失败返回-1.struct sembuf{short sem_num; //操作信号量在信号量集合中的编号,第一个信号量编号为0short sem_op; //sem_op为-1,就是p操作,即wait操作。为+1就是v操作,即signal操作。short sem_flg; //通常设为SEM_UNDO,程序结束,信号量为semop调用前的值。
};
**int semctl(int semid, int semnum, int cmd, …);**用来直接控制信号量的信息。成功返回0,失败返回-1。union semun{
int val; /* SETVAL的值 */
struct semid_ds *buf; /* IPC_STAT, IPC_SET的缓冲区 */
unsigned short *array; /* GETALL, SETALL的集合 */
};
相关结构体:
The semid_ds data structure is defined in
struct semid_ds {struct ipc_perm sem_perm; /* Ownership and permissions */time_t sem_otime; /* Last semop time */time_t sem_ctime; /* Last change time */unsigned long sem_nsems; /* No. of semaphores in set */
};
The ipc_perm structure is defined as follows (the highlighted fields aresettable using IPC_SET):
struct ipc_perm {key_t __key; /* Key supplied to semget(2) */uid_t uid; /* Effective UID of owner */gid_t gid; /* Effective GID of owner */uid_t cuid; /* Effective UID of creator */gid_t cgid; /* Effective GID of creator */unsigned short mode; /* Permissions */unsigned short __seq; /* Sequence number */
};
创建子进程生产V操作,放入信号集合中,在创建父进程消费P操作,放入信号集合中。
#include
#include
#include
#include
#include
#include
#include
#include
#include union semun //必须重写共用体
{int val; //信号量的值struct semid_ds* buf; //IPC_STAT, IPC_SET的缓冲区unsigned short *array; //GETALL,SETALL的数组
};int main()
{int semid = semget(IPC_PRIVATE,1,0666|IPC_CREAT); //创建信号量集if(semid == -1){ //创建失败的处理perror("semget error");exit(-1);}if(fork() == 0){ //子进程struct sembuf sem; //定义信号量结构体memset(&sem,0,sizeof(struct sembuf)); //初始化结构体sem.sem_num = 0; //信号量编号,初始为0sem.sem_op = 1; //+1 表示执行V操作,即signal生产产品sem.sem_flg = 0; //SEM_UNDO,设置semop调用前的值union semun arg; //arg.val = 0; //初始化信号量的值semctl(semid,0,SETALL,arg); //将信号量的值全部设置到信号量集中,相当于公共信号量while(1){semop(semid,&sem,1); //执行指定的V操作,表示生产者生产产品printf("生产者总数:%d\n",semctl(semid,0,GETVAL)); //打印生产的公共信号量sleep(1); //休息一秒if(semctl(semid,0,GETVAL) == 5){break;}}}else{ //父进程sleep(2); //休眠,让子进程先生产点东西struct sembuf sem; //信号量结构体memset(&sem,0,sizeof(struct sembuf)); //初始化结构体sem.sem_num = 0; //信号量编号,初始为0sem.sem_op = -1; //-1 表示执行P操作,即wait 消费产品sem.sem_flg = 0; //SEM_UNDO,设置semop调用前的值while(1){semop(semid,&sem,1); //执行指定的P操作,表示消费者消费产品printf("消费者总数:%d\n",semctl(semid,0,GETVAL)); //打印获取的公共信号量sleep(2); //休息两秒if(semctl(semid,0,GETVAL) == 0){break;}wait(NULL);}}return 0;
}
运行结果实例:两个if判断就是,子进程生产5个退出,父进程消费所有的退出。

生产者源码
#include
#include
#include
#include
#include
#include
#include
#include
#include
//定义全局变量信号集id
int sem_id;
//初始化信号集
void init();
//删除信号集
void del();int main()
{struct sembuf sops[2]; //定义两个信号量sops[0].sem_num = 0; //设置生产者编号0sops[0].sem_op = 1; //就是V操作,生产产品sops[0].sem_flg = 0; //也可以写成SEM_UNDOsops[1].sem_num = 1; //设置仓库容量编号0sops[1].sem_op = -1; //就是P操作,仓库容量-1sops[1].sem_flg = 0; //也可以写成SEM_UNDOinit();//初始化信号量集合,就是生产产品量和仓库空位printf("生产者开始生产\n");printf("生产的数量%d\n",semctl(sem_id,0,GETVAL));//使用semctl获取集合中第一个结构体中的valprintf("空闲空间为%d\n",semctl(sem_id,1,GETVAL));//使用semctl获取集合中第二个结构体中的valwhile(1){semop(sem_id,&sops[1],1); //改变第二个数组的中状态,即空闲仓库容量先-1,才能生产产品+1//先对仓库容量-1的原因是,如果有多个生产者同时生产,就需要用仓库容量来限制printf("已经申请了仓库,可以开始生产了\n");semop(sem_id,&sops[0],1); //改变第一个数组的中状态,即产品数量+1printf("空闲空间为%d\n",semctl(sem_id,1,GETVAL));//使用semctl获取集合中第二个结构体中的valprintf("生产的数量%d\n",semctl(sem_id,0,GETVAL));//使用semctl获取集合中第一个结构体中的valsleep(2);}del();//删除信号集合return 0;
}
//初始化信号集
void init()
{int ret;unsigned short sem_array[2];union semum{int val;struct semid_ds* buf;unsigned short* array;}arg;sem_id = semget((key_t)1234,2,IPC_CREAT|0644); //使用key创建一个还有两个信号的信号集if(sem_id == -1){perror("semget");exit(-1);}sem_array[0] = 0; //产品数量sem_array[1] = 10; //仓库空位arg.array = sem_array;ret = semctl(sem_id,0,SETALL,arg); //将所有semun.array的值设置到集合中,第二个参数代表0号if(ret == -1){ printf("信号量放入集合失败");}printf("生产者%d初始化\n",semctl(sem_id,0,GETVAL));printf("仓库%d初始化\n",semctl(sem_id,1,GETVAL));
}
//删除信号集
void del()
{semctl(sem_id,IPC_RMID,0);
}
消费者源码
#include
#include
#include
#include
#include
#include
#include
#include
#include int sem_id;
//获取生产者创建的信号集标识符
void init();
int main()
{struct sembuf sops[2];sops[0].sem_num = 0; //设置消费者编号0sops[0].sem_op = -1; //就是P操作,消费产品sops[0].sem_flg = 0; //也可以写成SEM_UNDOsops[1].sem_num = 0; //设置仓库容量编号0sops[1].sem_op = 1; //就是V操作,仓库容量+1sops[1].sem_flg = 0; //也可以写成SEM_UNDOinit();printf("这是消费者\n");printf("消费的数量%d\n",semctl(sem_id,0,GETVAL));//使用semctl获取集合中第一个结构体中的valprintf("空闲空间为%d\n",semctl(sem_id,1,GETVAL));//使用semctl获取集合中第二个结构体中的valwhile(1){semop(sem_id,&sops[0],1);//先消费,在归还仓库空间//原因是如果多个消费者同步消费,先归还仓库空间会导致,生产者快速填满,目的是为了生产者和消费者的同步printf("现在开始消费\n");semop(sem_id,&sops[1],1);//归还仓库空间printf("消费的数量%d\n",semctl(sem_id,0,GETVAL));//使用semctl获取集合中第一个结构体中的valprintf("空闲空间为%d\n",semctl(sem_id,1,GETVAL));//使用semctl获取集合中第二个结构体中的valsleep(1);}return 0;
}
//获取生产者创建的信号集标识符
void init()
{sem_id = semget((key_t)1234,2,IPC_CREAT|0644); //获取信号集ID
}
