亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 服務器 > Web服務器 > 正文

詳解Linux進程間通信——使用信號量

2024-09-01 13:50:25
字體:
來源:轉載
供稿:網友

一、什么是信號量

為了防止出現因多個程序同時訪問一個共享資源而引發的一系列問題,我們需要一種方法,它可以通過生成并使用令牌來授權,在任一時刻只能有一個執行線程訪問代碼的臨界區域。臨界區域是指執行數據更新的代碼需要獨占式地執行。而信號量就可以提供這樣的一種訪問機制,讓一個臨界區同一時間只有一個線程在訪問它,也就是說信號量是用來調協進程對共享資源的訪問的。

信號量是一個特殊的變量,程序對其訪問都是原子操作,且只允許對它進行等待(即P(信號變量))和發送(即V(信號變量))信息操作。最簡單的信號量是只能取0和1的變量,這也是信號量最常見的一種形式,叫做二進制信號量。而可以取多個正整數的信號量被稱為通用信號量。這里主要討論二進制信號量。

二、信號量的工作原理

由于信號量只能進行兩種操作等待和發送信號,即P(sv)和V(sv),他們的行為是這樣的:

P(sv):如果sv的值大于零,就給它減1;如果它的值為零,就掛起該進程的執行

V(sv):如果有其他進程因等待sv而被掛起,就讓它恢復運行,如果沒有進程因等待sv而掛起,就給它加1.

舉個例子,就是兩個進程共享信號量sv,一旦其中一個進程執行了P(sv)操作,它將得到信號量,并可以進入臨界區,使sv減1。而第二個進程將被阻止進入臨界區,因為當它試圖執行P(sv)時,sv為0,它會被掛起以等待第一個進程離開臨界區域并執行V(sv)釋放信號量,這時第二個進程就可以恢復執行。

三、Linux的信號量機制

Linux提供了一組精心設計的信號量接口來對信號進行操作,它們不只是針對二進制信號量,下面將會對這些函數進行介紹,但請注意,這些函數都是用來對成組的信號量值進行操作的。它們聲明在頭文件sys/sem.h中。

1、semget函數

它的作用是創建一個新信號量或取得一個已有信號量,原型為:

int semget(key_t key, int num_sems, int sem_flags); 

第一個參數key是整數值(唯一非零),不相關的進程可以通過它訪問一個信號量,它代表程序可能要使用的某個資源,程序對所有信號量的訪問都是間接的,程序先通過調用semget函數并提供一個鍵,再由系統生成一個相應的信號標識符(semget函數的返回值),只有semget函數才直接使用信號量鍵,所有其他的信號量函數使用由semget函數返回的信號量標識符。如果多個程序使用相同的key值,key將負責協調工作。

第二個參數num_sems指定需要的信號量數目,它的值幾乎總是1。

第三個參數sem_flags是一組標志,當想要當信號量不存在時創建一個新的信號量,可以和值IPC_CREAT做按位或操作。設置了IPC_CREAT標志后,即使給出的鍵是一個已有信號量的鍵,也不會產生錯誤。而IPC_CREAT | IPC_EXCL則可以創建一個新的,唯一的信號量,如果信號量已存在,返回一個錯誤。

semget函數成功返回一個相應信號標識符(非零),失敗返回-1.

2、semop函數

它的作用是改變信號量的值,原型為:

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops); 

sem_id是由semget返回的信號量標識符,sembuf結構的定義如下:

struct sembuf{   short sem_num;//除非使用一組信號量,否則它為0   short sem_op;//信號量在一次操作中需要改變的數據,通常是兩個數,一個是-1,即P(等待)操作,           //一個是+1,即V(發送信號)操作。   short sem_flg;//通常為SEM_UNDO,使操作系統跟蹤信號,           //并在進程沒有釋放該信號量而終止時,操作系統釋放信號量 }; 

3、semctl函數

該函數用來直接控制信號量信息,它的原型為:

int semctl(int sem_id, int sem_num, int command, ...); 

如果有第四個參數,它通常是一個union semum結構,定義如下:

union semun{   int val;   struct semid_ds *buf;   unsigned short *arry; }; 

前兩個參數與前面一個函數中的一樣,command通常是下面兩個值中的其中一個

  • SETVAL:用來把信號量初始化為一個已知的值。p 這個值通過union semun中的val成員設置,其作用是在信號量第一次使用前對它進行設置。
  • IPC_RMID:用于刪除一個已經無需繼續使用的信號量標識符。

四、進程使用信號量通信

下面使用一個例子來說明進程間如何使用信號量來進行通信,這個例子是兩個相同的程序同時向屏幕輸出數據,我們可以看到如何使用信號量來使兩個進程協調工作,使同一時間只有一個進程可以向屏幕輸出數據。注意,如果程序是第一次被調用(為了區分,第一次調用程序時帶一個要輸出到屏幕中的字符作為一個參數),則需要調用set_semvalue函數初始化信號并將message字符設置為傳遞給程序的參數的第一個字符,同時第一個啟動的進程還負責信號量的刪除工作。如果不刪除信號量,它將繼續在系統中存在,即使程序已經退出,它可能在你下次運行此程序時引發問題,而且信號量是一種有限的資源。

在main函數中調用semget來創建一個信號量,該函數將返回一個信號量標識符,保存于全局變量sem_id中,然后以后的函數就使用這個標識符來訪問信號量。

源文件為seml.c,代碼如下:

#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);     sleep(rand() % 3);     //離開臨界區前再一次向屏幕輸出數據     printf("%c", message);     fflush(stdout);     //離開臨界區,休眠隨機時間后繼續循環     if(!semaphore_v())       exit(EXIT_FAILURE);     sleep(rand() % 2);   }    sleep(10);   printf("/n%d - finished/n", getpid());    if(argc > 1)   {     //如果程序是第一次被調用,則在退出前刪除信號量     sleep(3);     del_semvalue();   }   exit(EXIT_SUCCESS); }  static int set_semvalue() {   //用于初始化信號量,在使用信號量前必須這樣做   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)     fprintf(stderr, "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)   {     fprintf(stderr, "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)   {     fprintf(stderr, "semaphore_v failed/n");     return 0;   }   return 1; } 

運行結果如下:

 linux,進程間,信號量,進程,進程通信

注:這個程序的臨界區為main函數for循環不的semaphore_p和semaphore_v函數中間的代碼。

例子分析 :同時運行一個程序的兩個實例,注意第一次運行時,要加上一個字符作為參數,例如本例中的字符‘O',它用于區分是否為第一次調用,同時這個字符輸出到屏幕中。因為每個程序都在其進入臨界區后和離開臨界區前打印一個字符,所以每個字符都應該成對出現,正如你看到的上圖的輸出那樣。在main函數中循環中我們可以看到,每次進程要訪問stdout(標準輸出),即要輸出字符時,每次都要檢查信號量是否可用(即stdout有沒有正在被其他進程使用)。

所以,當一個進程A在調用函數semaphore_p進入了臨界區,輸出字符后,調用sleep時,另一個進程B可能想訪問stdout,但是信號量的P請求操作失敗,只能掛起自己的執行,當進程A調用函數semaphore_v離開了臨界區,進程B馬上被恢復執行。然后進程A和進程B就這樣一直循環了10次。

五、對比例子——進程間的資源競爭

看了上面的例子,你可能還不是很明白,不過沒關系,下面我就以另一個例子來說明一下,它實現的功能與前面的例子一樣,運行方式也一樣,都是兩個相同的進程,同時向stdout中輸出字符,只是沒有使用信號量,兩個進程在互相競爭stdout。它的代碼非常簡單,文件名為normalprint.c,代碼如下:

#include <stdio.h> #include <stdlib.h>  int main(int argc, char *argv[]) {   char message = 'X';   int i = 0;    if(argc > 1)     message = argv[1][0];   for(i = 0; i < 10; ++i)   {     printf("%c", message);     fflush(stdout);     sleep(rand() % 3);     printf("%c", message);     fflush(stdout);     sleep(rand() % 2);   }   sleep(10);   printf("/n%d - finished/n", getpid());   exit(EXIT_SUCCESS); } 

運行結果如下:

linux,進程間,信號量,進程,進程通信

例子分析:

從上面的輸出結果,我們可以看到字符‘X'和‘O'并不像前面的例子那樣,總是成對出現,因為當第一個進程A輸出了字符后,調用sleep休眠時,另一個進程B立即輸出并休眠,而進程A醒來時,再繼續執行輸出,同樣的進程B也是如此。所以輸出的字符就是不成對的出現。這兩個進程在競爭stdout這一共同的資源。通過兩個例子的對比,我想信號量的意義和使用應該比較清楚了。

六、信號量的總結

信號量是一個特殊的變量,程序對其訪問都是原子操作,且只允許對它進行等待(即P(信號變量))和發送(即V(信號變量))信息操作。我們通常通過信號來解決多個進程對同一資源的訪問競爭的問題,使在任一時刻只能有一個執行線程訪問代碼的臨界區域,也可以說它是協調進程間的對同一資源的訪問權,也就是用于同步進程的。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲一区二区三区四区视频| 成人xvideos免费视频| 亚洲片国产一区一级在线观看| 欧美日韩精品中文字幕| 亚洲国产精品va在线看黑人动漫| 91久久久久久久久久久久久| 亚洲精品久久久久久久久久久久久| 青青在线视频一区二区三区| 久久777国产线看观看精品| 国产视频精品在线| 成人福利网站在线观看| 亚洲精品国产suv| 久久亚洲精品一区| 日本亚洲欧美成人| 亚洲精品资源美女情侣酒店| 成人福利网站在线观看| 中文字幕精品网| 日韩一区二区福利| 亚洲图中文字幕| 亚洲色图激情小说| 国产精品一久久香蕉国产线看观看| 久久精品国产2020观看福利| 欧美老少配视频| 95av在线视频| 国产精品久久久久久亚洲调教| 国产偷国产偷亚洲清高网站| 欧美性xxxxx极品娇小| 国产精品户外野外| 欧美性感美女h网站在线观看免费| 日韩高清不卡av| 国产69精品99久久久久久宅男| 亚洲第一视频网站| 2019中文字幕全在线观看| 国产精品国产亚洲伊人久久| 国产精品入口免费视频一| 国产精品黄色影片导航在线观看| 色噜噜久久综合伊人一本| 91精品国产九九九久久久亚洲| 日韩av一卡二卡| 国产91对白在线播放| 国产欧美日韩综合精品| 少妇高潮久久久久久潘金莲| 国产一区二区三区视频在线观看| 91欧美精品成人综合在线观看| 欧美日韩中文字幕在线视频| 欧美性在线视频| 亚洲国产精品福利| 精品国内亚洲在观看18黄| 亚洲人成电影在线观看天堂色| 欧美激情网站在线观看| 中日韩美女免费视频网址在线观看| 日韩免费av一区二区| 国产男人精品视频| 国产精品久久久久久久久久久不卡| 不卡在线观看电视剧完整版| 在线观看国产精品91| 久久频这里精品99香蕉| 57pao成人国产永久免费| 在线播放国产精品| 一区二区三区四区视频| 国产一区二区三区视频| 亚洲第一区在线观看| 欧美性猛交xxxxx免费看| 成人激情视频在线观看| 国产精品盗摄久久久| 久久精品人人爽| 国产综合久久久久久| 午夜精品在线视频| 一区二区三区高清国产| 日韩在线激情视频| 精品福利樱桃av导航| 成人免费观看49www在线观看| 国产精品r级在线| 日韩欧美中文在线| 午夜美女久久久久爽久久| 日韩高清免费在线| 国产亚洲精品久久久久动| 国产精品第二页| 少妇高潮久久久久久潘金莲| 亚洲性av在线| 日韩高清a**址| 久热精品视频在线观看一区| 欧美性猛交xxxx免费看久久久| 久久久精品欧美| 日韩中文字幕在线视频| 久久久久久国产精品| 不卡av电影院| 精品国产一区二区在线| 国产精品96久久久久久又黄又硬| 中文字幕欧美日韩va免费视频| 日韩av黄色在线观看| 亚洲国产黄色片| 在线午夜精品自拍| 久久人人爽人人爽人人片av高请| 欧美激情成人在线视频| 超碰精品一区二区三区乱码| 国产91精品黑色丝袜高跟鞋| 羞羞色国产精品| 亚洲第一区中文99精品| 欧美最猛黑人xxxx黑人猛叫黄| 中文字幕久久久| 国产美女久久精品香蕉69| 国产精品视频免费在线观看| 国产精品久久91| 国产精品一久久香蕉国产线看观看| 欧美激情网站在线观看| 国产成人一区三区| 国产精品直播网红| 久久久国产精彩视频美女艺术照福利| 欧美性受xxxx白人性爽| 国产午夜精品理论片a级探花| 国产午夜精品一区理论片飘花| 成人h猎奇视频网站| 亚洲男人天堂九九视频| 中文字幕日韩欧美在线视频| 亚洲人成电影在线| 午夜精品美女自拍福到在线| 日韩中文字幕在线精品| 欧美激情精品久久久| 亚洲精品欧美一区二区三区| 欧美国产精品va在线观看| 国产69精品久久久久9999| 视频一区视频二区国产精品| 激情久久av一区av二区av三区| 亚洲国内精品在线| 国产精品美女主播在线观看纯欲| 久久国产精品免费视频| 欧美成人第一页| 国语自产精品视频在线看抢先版图片| 欧日韩不卡在线视频| 久久免费成人精品视频| 欧洲成人免费视频| 国产精品中文字幕在线观看| 日韩av在线一区| 最新的欧美黄色| 欧美主播福利视频| 精品中文字幕在线2019| 国产免费一区二区三区香蕉精| 欧美激情视频三区| 中文字幕欧美精品在线| 欧美极品第一页| 亚洲精品美女免费| 久久精品人人爽| 91精品视频在线看| 久久久久久久成人| 美日韩精品视频免费看| 国产精品视频午夜| 欧美日韩中文字幕在线视频| 精品久久久香蕉免费精品视频| 久久成人精品一区二区三区| 亚洲女人天堂成人av在线| 国产精品一二三视频| 91在线观看免费| 国产99久久精品一区二区永久免费| 91亚洲精品在线| 久久久日本电影| 国产欧美久久久久久| 亚洲一区精品电影| 亚洲免费电影一区| 精品久久久久久久久久久久| 欧美激情视频网站| 欧美精品18videos性欧| 97超级碰在线看视频免费在线看| 国产精品视频xxxx|