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操做