1. 程式人生 > >Linux進程間通信---信號量

Linux進程間通信---信號量

creat 程序 pid == 對象 數據對象 tpi -- lee

  • 信號量是一個計數器,通常在內核中實現,用於多個進程對共享數據對象的同步訪問。使用信號量的頭文件是#include <sys/sem.h>
  • 信號量的使用規則:
    • 若信號量為正,則進程可使用該資源。
    • 若信號量為0,則進程阻塞等待,並將進程插入等待隊列,直到該信號量的值大於0從等待隊列中執行進程請求。
    • 加鎖操作:如果信號量大於0,則信號量-1;如果信號量為0,則掛起該進程,並將這個進程插入等待隊列。
    • 解鎖操作:如果等待隊列中有進程則喚醒該進程,讓它恢復運行;否則,信號量+1。
  • Linux下使用信號量的常用函數:
    • semget(key, num_sems, sem_flags):創建新的信號量或取得已有的信號量,key表示信號量的鍵值,不相關進程使用同一個key來訪問同一個信號量,num_sems表示信號量個數(一般為1),sem_flags表示信號量訪問權限,用IPC_CREAT與權限位與可保證信號量不存在時新建一個。函數返回一個int類型的數值,表示信號量的標識符。
    • semop(sem_id, sem_opa, num_sem_ops):改變信號量的值,改變操作在sem_opa中,sem_opa是sumbuf結構體對象,使用方法如下:
      struct sembuf
      {  
         short sem_num;   //除非使用一組信號量,否則它為0  
         short sem_op;    //信號量在一次操作中需要改變的數據,通常是兩個數,一個是-1,即P操作(加鎖);一個是+1,即V操作(解鎖)
         short sem_flg;   //通常為SEM_UNDO,使操作系統跟蹤信號,並在進程沒有釋放該信號量而終止時,操作系統釋放信號量  
      };
    • semctl(sem_id, sem_num, command, semun):控制信號量。commond中有:SETVAL初始化信號量為一個值,該值再semun結構體的val字段;IPC_RMID用於刪除一個無需繼續使用的信號量。
  • 信號量的使用實例,同時開兩個進程,每個進程中都用信號量同步臨界區,在臨界區中向屏幕打印字符:
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include 
    <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/sem.h> union semun { int val; struct semid_ds *buf; unsigned short *arry; }; static int sem_id = 0; static int set_semvalue(); static void del_semvalue(); static int semaphore_p(); static int semaphore_v(); int main(int argc, char *argv[]) { char message = X; int i = 0; //創建信號量 sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT); if(argc > 1) { //程序第一次被調用,初始化信號量 if(!set_semvalue()) { fprintf(stderr, "Failed to initialize semaphore\n"); exit(EXIT_FAILURE); } //設置要輸出到屏幕中的信息,即其參數的第一個字符 message = argv[1][0]; sleep(2); } for(i = 0; i < 10; ++i) { //進入臨界區 if(!semaphore_p()) exit(EXIT_FAILURE); //向屏幕中輸出數據 printf("%c", message); //清理緩沖區,然後休眠隨機時間 fflush(stdout); //離開臨界區,休眠隨機時間後繼續循環 if(!semaphore_v()) exit(EXIT_FAILURE); sleep(2); } sleep(3); printf("\n%d - finished\n", getpid()); if(argc > 1) { //如果程序是第一次被調用,則在退出前刪除信號量 sleep(3); del_semvalue(); } exit(EXIT_SUCCESS); } static int set_semvalue() { //用於初始化信號量,在sem_union的val字段中設置信號量初值。使用信號量之前必須先初始化! union semun sem_union; sem_union.val = 1; if(semctl(sem_id, 0, SETVAL, sem_union) == -1) return 0; return 1; } static void del_semvalue() { //刪除信號量 union semun sem_union; if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1) printf("Failed to delete semaphore\n"); } static int semaphore_p() { //對信號量做減1操作,即加鎖 P(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1; //P() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_p failed\n"); return 0; } return 1; } static int semaphore_v() { //這是一個釋放操作,它使信號量變為可用,即解鎖 V(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; //V() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_v failed\n"); return 0; } return 1; }
  ps:以上代碼參考自https://blog.csdn.net/ljianhui/article/details/10243617,運行結果如下: 技術分享圖片

Linux進程間通信---信號量