1.特色: 信号灯集,是控制访问临界资源数组
信号灯(semaphore),也叫信号量。它是不一样进程间或一个给定进程内部不一样线程间同步的机制System V的信号灯是一个或者多个信号灯的一个集合(容许对集合中的多个计数信号灯进行同时操做)。其中的每个都是单独的计数信号灯。而Posix信号灯指的是单个计数信号灯
2.信号灯种类:
posix有名信号灯
posix基于内存的信号灯(无名信号灯)(线程)
System V信号灯(IPC对象)(信号灯的值就是表明资源的数量)app
3.建立步骤:
1)产生key值
2)建立信号灯集
3)初始化信号灯(对信号灯集中的每一个信号灯进行初始化)
4)信号灯的P-V操做
5)删除信号灯集函数
4.相关函数:
1)int semget(key_t key, int nsems, int semflg);
功能:建立/打开信号灯
参数:key:ftok产生的key值(和信号灯关联的key值)
nsems:信号灯集中包含的信号灯数目
semflg:信号灯集的访问权限,一般为IPC_CREAT |0666
返回值:成功:信号灯集ID ; 失败:-1测试
2)int semop ( int semid, struct sembuf *opsptr, size_t nops);
功能:对信号灯集合中的信号量进行P - V操做
参数:semid:信号灯集ID
struct sembuf {
short sem_num; // 要操做的信号灯的编号
short sem_op; // 0 : 等待,直到信号灯的值变成0 // 1 : 释放资源,V操做 // -1 : 分配资源,P操做
short sem_flg; // 0(阻塞),IPC_NOWAIT, SEM_UNDO
};//对某一个信号灯的操做,若是同时对多个操做,则须要定义这种结构体数组spa
nops: 要操做的信号灯的个数 ,1个
返回值:成功 :0 ; 失败:-1线程
用法:semop(semid, &mysembuf, 1);
申请资源 P操做:
mysembuf.sem_num = 0;
mysembuf.sem_op = -1;
mysembuf.sem_flg = 0;
释放资源 V操做:
mysembuf.sem_num = 0;
mysembuf.sem_op = 1;
mysembuf.sem_flg = 0;code
3)int semctl ( int semid, int semnum, int cmd…/*union semun arg*/);
功能:信号灯集合的控制(初始化/删除)
参数:semid:信号灯集ID
semnum: 要操做的集合中的信号灯编号
cmd:
GETVAL:获取信号灯的值,返回值是得到值
SETVAL:设置信号灯的值,须要用到第四个参数:共用体
IPC_RMID:从系统中删除信号灯集合
返回值:成功 0 ; 失败 -1对象
用法:
初始化:semctl(semid, 0, SETVAL, mysemun);
须要在程序中定义共用体
获取信号灯值:semctl(semid, 0, GETVAL);
删除信号灯集:semctl(semid, 0, IPC_RMID);blog
例子: 简单对信号灯的操做(多值信号灯)进程
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <errno.h> int semid; //信号灯集id, 经过这个id 操做这个信号灯集,在不一样进程中,操做同一个信号灯集的id union semnum { int val; }; union semnum mynum; struct sembuf mybuf; //定义操做信号灯的结构 //参数 信号灯集id 和 是哪一个信号灯 void sem_p(int semid, unsigned short num) //P操做函数 { mybuf.sem_num = num; //第一个信号灯,(信号灯编号) mybuf.sem_op = -1; //进行P操做, 为 1 时表示V操做 mybuf.sem_flg = 0; //阻塞 semop(semid, &mybuf, 1); //最后一个参数,表示操做信号灯的个数 } //参数 信号灯集id 和 是哪一个信号灯 void sem_v(int semid, unsigned short num) //V操做函数 { mybuf.sem_num = num; mybuf.sem_op = 1; //1 表示V 操做 mybuf.sem_flg = 0; //阻塞 semop(semid, &mybuf, 1); //操做的 mybuf 所有变量信号灯集 } int main(int argc, const char *argv[]) { key_t key; key = ftok("app",'m');//获取惟一的 key if(key < 0) { perror("fail fptk "); exit(1); } //int semget(key_t key, int nsems, int semflg); //IPC_EXCL | IPC_CREAT 信号灯不存在就建立 semid = semget(key, 2, IPC_CREAT|IPC_EXCL|0666); //建立信号灯,IPC_EXCL 问信号灯存不存在 if(semid < 0) { if(errno == EEXIST)//存在时,只须要打开便可 { semid = semget(key,2,0666); //打开信号灯 } else { perror("semget fail "); } } else { // int semctl(int semid, int semnum, int cmd, ...); mynum.val = 10; //设置信号灯值 semctl(semid,0,SETVAL,mynum); //初始化 0 号信号灯,此处使用共用体设置信号灯值,初始化完成后能够继续给下一个信号灯设置值 mynum.val = 5; //设置信号灯值 semctl(semid,1,SETVAL,mynum); //初始化 1 号信号灯,把设置的信号灯值给1号信号灯 } sem_p(semid, 0); //对semid 指向的信号灯集,中0号信号灯进行P操做 sem_p(semid, 0); //对semid 指向的信号灯集,中0号信号灯进行P操做 sem_p(semid, 0); //对semid 指向的信号灯集,中0号信号灯进行P操做 printf("%d\n",semctl(semid, 0, GETVAL)); //上面对 0 信号灯初始值 10 进行流三次P 操做,此时应该为 7 printf("%d\n",semctl(semid, 1, GETVAL)); //没有对 1 信号灯操做,其值不变为 5 putchar(10); sem_v(semid,1); printf("%d\n",semctl(semid, 1, GETVAL)); //上面对 1 信号灯 V 操做,其值变为 6 semctl(semid,0,IPC_RMID);//删除信号灯 return 0; }
测试:对于多值信号灯能够进行屡次P操做