Linux 進程間通訊 信號燈集

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

相關文章
相關標籤/搜索