1. 程式人生 > >程序間通訊-訊號量詳解及程式設計例項

程序間通訊-訊號量詳解及程式設計例項

前面一篇文章執行緒同步之訊號量同步 講的是執行緒之間的訊號量,這篇講的更加具有通用性,能夠實現程序之間的同步

訊號量概述

訊號量定義:

它是一個特殊變數,只允許對它進行等待和傳送訊號這兩種操作

  • P(訊號量變數sv):等待如果sv大於0,減小sv。如果sv為0,掛起這個程序的執行
  • V(訊號量變數sv):傳送訊號。如果有程序被掛起等待sv,使其恢復執行。如果沒有進行被掛起等待sv,增加sv

PV操作虛擬碼

[cpp] view plaincopyprint?
  1. semaphore sem_id = 1;  
  2. loop{  
  3.     P(sem_id);  
  4.    臨界區程式碼;  
  5.     V(sem_id);  
  6.      非臨界區程式碼;  
  7. }  

訊號量機制及相關介面

Linux系統中的訊號量介面經過了精心設計,提供了比通常所需更多的機制。所有的Linux訊號量函式都是針對成組的通用訊號量進行操作,而不只是針對一個二進位制訊號量。但是在絕大多數情況下,使用一個單個訊號量就足夠了,所以在這裡只討論單個訊號量的使用。

semget函式

用於建立一個新的訊號量或者是取得一個已有的訊號量的鍵。

所需包含的標頭檔案:

[cpp] view plaincopyprint?
  1. #include <sys/sem.h> 
它通常依賴於另兩個標頭檔案:
[cpp] view plaincopyprint?
  1. #include <sys/types.h>
  2. #include <sys/ipc.h> 
一般情況下,這兩個標頭檔案都會被它自動包含。

功能描述
  函式原型:int semget(key_t key,int nsems,int semflg);
  功能描述
  獲取與某個鍵關聯的訊號量集標識。訊號量集被建立的情況有兩種:
  1.如果鍵的值是IPC_PRIVATE。
  2.或者鍵的值不是IPC_PRIVATE,並且鍵所對應的訊號量集不存在,同時標誌中指定IPC_CREAT。
  當呼叫semget建立一個訊號量時,他的相應的semid_ds結構被初始化。ipc_perm中各個量被設定為相應
  值:
  sem_nsems被設定為nsems所示的值;
  sem_otime被設定為0;
  sem_ctime被設定為當前時間

引數解釋

       key:所建立或開啟訊號量集的鍵值。需要是唯一的非零整數
  nsems:建立的訊號量集中的訊號量的個數,該引數只在建立訊號量集時有效。幾乎總是取值為1.
  flag:呼叫函式的操作型別,也可用於設定訊號量集的訪問許可權,兩者通過or表示


返回值說明:
  如果成功,則返回訊號量集的IPC識別符號(一個正數)。
  如果失敗,則返回-1,errno被設定成以下的某個值
  EACCES:沒有訪問該訊號量集的許可權
  EEXIST:訊號量集已經存在,無法建立
  EINVAL:引數nsems的值小於0或者大於該訊號量集的限制;或者是該key關聯的訊號量集已存在,並且nsems
  大於該訊號量集的訊號量數
  ENOENT:訊號量集不存在,同時沒有使用IPC_CREAT
  ENOMEM :沒有足夠的記憶體建立新的訊號量集
  ENOSPC:超出系統限制

semop函式

用於改變訊號量的值。

[cpp] view plaincopyprint?
  1. #include <sys/sem.h>
  2. int semop( int semid, struct sembuf saremopray[], size_t nops );   

引數解釋:

引數semid是一個通過semget函式返回的一個訊號量識別符號

引數nops標明瞭引數semoparray所指向陣列中的元素個數

引數semoparray是一個struct sembuf結構型別的陣列指標

結構sembuf來說明所要執行的操作,其定義如下:
  

[cpp] view plaincopyprint?
  1. struct sembuf{  
  2.   unsigned short sem_num;  
  3.   short sem_op;  
  4.   short sem_flg;  
  5.   }  

在sembuf結構中,

sem_num是相對應的訊號量集中的某一個資源,所以其值是一個從0到相應的訊號量集的資源總數(ipc_perm.sem_nsems)之間的整數。除非使用一組訊號了,否則它的取值一般為0.

sem_op的值是一個整數,是訊號量在一次操作中需要改變的數值(可以是非1的數值)。通常只會用到兩個值:1----P操作,-1---V操作。

sem_flg說明函式semop的行為。通常被設定為SEM_UNDO。它將使得作業系統跟著當前程序對這個訊號量的修改情況,如果這個程序在沒有釋放該訊號量的情況下終止,作業系統將自動釋放該程序持有的訊號量。

注意:

semop呼叫的一切動作都是一次性完成的,這是為了避免出現因使用多個訊號量而可能發生的競爭現象。

semctl函式


原型:

[cpp] view plaincopyprint?
  1. int semctl(int semid,int semnum,int cmd,union semun);  

返回值:

       如果成功,則為一個正數。
  如果失敗,則為-1:

errno=EACCESS(許可權不夠)
  EFAULT(arg指向的地址無效)
  EIDRM(訊號量集已經刪除)
  EINVAL(訊號量集不存在,或者semid無效)
  EPERM(EUID沒有cmd的權利)
  ERANGE(訊號量值超出範圍) 

引數解釋:

sem_id是由semget返回的訊號量識別符號。

sem_num與前面一個函式相同。

cnd:表示將要採取的動作。最常用的兩個值如下:

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

semun聯合結構的定義:

[cpp] view plaincopyprint?
  1. semun是在linux/sem.h中定義的:  
  2.   /*arg for semctl systemcalls.*/
  3.   union semun{  
  4.   int val;/*value for SETVAL*/
  5.   struct semid_ds *buf;/*buffer for IPC_STAT&IPC_SET*/
  6.   ushort *array;/*array for GETALL&SETALL*/
  7.   struct seminfo *__buf;/*buffer for IPC_INFO*/
  8.   void *__pad;   

訊號量的使用

雖然上述函式呼叫看似很複雜,但是我們可以用這些介面來建立一個簡單的PV型別的介面,然後用這個簡單的介面來進行訊號量相關操作。

下面的程式使用上述介面實現了P、V操組以及設定訊號量、刪除訊號量的操作。

然後利用這些新的函式介面實現了兩個程式例項訪問臨界區的功能。

在這裡同時訪問臨界區的是一個程式的兩個不同例項,並且使用引數個數的不同來進行區別。其中一個需要完成訊號量的建立及其刪除的額外操作。

兩個程式在進入臨界區和離開臨界區的時候分別都會輸出兩個不同的字元,以此來進行區分。可以發現,兩個不同的字元是成對出現的。因為同一時刻只有一個程序可以進入臨界區。

完整程式碼:

[cpp] view plaincopyprint?
  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <sys/sem.h>//包含訊號量定義的標頭檔案
  5. //聯合型別semun定義
  6. union semun{  
  7.     int val;  
  8.     struct semid_ds *buf;  
  9.     unsigned short *array;  
  10. };  
  11. //函式宣告
  12. //函式:設定訊號量的值
  13. staticint set_semvalue(void);  
  14. //函式:刪除訊號量
  15. staticvoid del_semvalue(void);  
  16. //函式:訊號量P操作
  17. staticint semaphore_p(void);  
  18. //函式:訊號量V操作
  19. staticint semaphore_v(void);  
  20. staticint sem_id;//訊號量ID
  21. int main(int argc,char *argv[])  
  22. {  
  23.     int i;  
  24.     int pause_time;  
  25.     char op_char = 'O';  
  26.     srand((unsigned int)getpid());  
  27.     //建立一個新的訊號量或者是取得一個已有訊號量的鍵
  28.     sem_id = semget((key_t)1234,1,0666 | IPC_CREAT);  
  29.     //如果引數數量大於1,則這個程式負責建立訊號和刪除訊號量
  30.     if(argc > 1)  
  31.     {  
  32.         if(!set_semvalue())  
  33.         {  
  34.             fprintf(stderr,"failed to initialize semaphore\n");  
  35.         exit(EXIT_FAILURE);  
  36.         }  
  37.         op_char = 'X';//對程序進行標記
  38.         sleep(5);  
  39.     }  
  40.     //迴圈:訪問臨界區
  41.     for(i = 0;i < 10;++i)  
  42.     {  
  43.         //P操作,嘗試進入緩衝區
  44.         if(!semaphore_p())  
  45.         exit(EXIT_FAILURE);  
  46.         printf("%c",op_char);  
  47.         fflush(stdout);//重新整理標準輸出緩衝區,把輸出緩衝區裡的東西列印到標準輸出裝置上
  48.         pause_time = rand() % 3;  
  49.         sleep(pause_time);  
  50.         printf("%c",op_char);  
  51.         fflush(stdout);  
  52.         //V操作,嘗試離開緩衝區
  53.         if(!semaphore_v())  
  54.         exit(EXIT_FAILURE);  
  55.         pause_time = rand() % 2;  
  56.         sleep(pause_time);  
  57.     }  
  58.     printf("\n %d - finished \n",getpid());  
  59.     if(argc > 1)  
  60.     {  
  61.         sleep(10);  
  62.         del_semvalue();//刪除訊號量
  63.     }  
  64. }  
  65. //函式:設定訊號量的值
  66. staticint set_semvalue(void)  
  67. {  
  68.     union semun sem_union;  
  69.     sem_union.val = 1;  
  70.     if(semctl(sem_id,0,SETVAL,sem_union))  
  71. 相關推薦

    【Linux】程序通訊-訊號程式設計例項

    前面一篇文章執行緒同步之訊號量同步 講的是執行緒之間的訊號量,這篇講的更加具有通用性,能夠實現程序之間的同步。 訊號量概述 訊號量定義: 它是一個特殊變數,只允許對它進行等待和傳送訊號這兩種操作。 P(訊號量變數sv):等待。如果sv大於0,減小sv。如果sv為0,掛起這

    程序通訊--訊號程式設計例項

    訊號量概述 訊號量定義: 它是一個特殊變數,只允許對它進行等待和傳送訊號這兩種操作。 P(訊號量變數sv):等待。如果sv大於0,減小sv。如果sv為0,掛起這個程序的執行。V(訊號量變數sv):傳送訊號。如果有程序被掛起等待sv,使其恢復執行。如果沒有進行被掛起等待sv

    程序通訊-訊號程式設計例項

    前面一篇文章執行緒同步之訊號量同步 講的是執行緒之間的訊號量,這篇講的更加具有通用性,能夠實現程序之間的同步。 訊號量概述 訊號量定義: 它是一個特殊變數,只允許對它進行等待和傳送訊號這兩種操作。 P(訊號量變數sv):等待。如果sv大於0,減小sv。如果sv為0,掛

    php程序通訊--訊號

     訊號量是什麼? 訊號量 : 又稱為訊號燈、旗語 用來解決程序(執行緒同步的問題),類似於一把鎖,訪問前獲取鎖(獲取不到則等待),訪問後釋放鎖。   舉一個生活中的例子:以一個停車場的運作為例。簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許

    Linux程式設計學習筆記----System V程序通訊(訊號)

    關於System V Unix System V,是Unix作業系統眾多版本中的一支。它最初由AT&T開發,在1983年第一次釋出,因此也被稱為AT&T System V。一共發行了4個System V的主要版本:版本1、2、3和4。System V Rel

    linux程序通訊-訊號

    引入訊號量之前,先介紹幾個概念: 1.臨界資源:同一時刻只允許一個程序或執行緒訪問的資源。(有時候是有限個程序或執行緒訪問),就比如一支筆一次只能是一個人使用。 這裡的臨界資源在c語言或c++中的表

    linux的程序通訊——訊號

    訊號量的本質是一種資料操作鎖,它本⾝身不具有資料交換的功能,而是通過控制其他的通訊資源(檔案,外部裝置)來實現程序間通訊,它本身只是一種外部資源的標識。訊號量在此過程中負責資料操作的互斥、同步等功能。當請求一個使⽤用訊號量來表⽰示的資源時,程序需要先讀取訊號量的

    【Linux】程序通訊(IPC)之訊號與測試用例

    學習環境centos6.5 Linux核心2.6 程序間通訊概述 1. 程序通訊機制 一般情況下,系統中執行著大量的程序,而每個程序之間並不是相互獨立的,有些程序之間經常需要互相傳遞訊息。但是每個程序在系統中都有自己的地址空間,作業系統通過頁表

    Linux程序通訊--訊號,管道,訊息佇列,訊號,共享記憶體,socket

    Linux 傳統的程序間通訊有很多,如各類管道、訊息佇列、記憶體共享、訊號量等等。但它們都無法介於核心態與使用者態使用,原因如表 通訊方法 無法介於核心態與使用者態的原因 管道(不包括命名管道) 侷限於父子程序間的通訊。 訊息佇列 在硬、軟中斷中無法無阻塞地接收資料。 訊號量 無法介於核

    搬家行業開發小程序系統(App.Config讀寫操作)

    設置 反饋 流程 選擇 文件的 搬家 功能 操作 服務項目 應用程序配置文件是標準的 XML 文件,XML 標記和屬性是區分大小寫的。它是可以按需要更改的,開發人員可以使用配置文件來更改設置,而不必重編譯應用程序。配置文件的根節點是configuration。我們經常訪問的

    Python第二天: 變賦值

    number ont 時間 目錄 命令 code toc 編號 運用 目錄 [toc] 此文章針對剛學Python的小白,若覺得對變量有很好的掌握,可以觀看其他的文章在這裏, 我說一下我對變量的簡單總結: 變量是為了存儲運算程序中的一些中間結果, 為了方便日後調用 什麽

    php程序通訊--訊號

    php程序間通訊的另外一個手段就是通過 訊號 來在程序間傳遞資訊。訊號是一種系統呼叫。通常我們用的kill命令就是傳送某個訊號給某個程序的。具體有哪些訊號可以在liunx/mac中執行kill -l檢視。 一些php訊號的意思如下: SIGHUP 終止程序

    Linux 程序通訊 --- 訊號通訊

    訊號  ( signal ) 機制是 UNIX 系統中最為古老的程序間通訊機制,很多條件可以產生一個訊號. 訊號的產生:           1,當用戶按下某些按鍵時,產生訊號.           2,硬體異常產生訊號:除數為 0 ,無效的儲存訪問等等.這些情況通常由硬

    程序通訊——訊號

    程序間通訊——訊號 宗旨:技術的學習是有限的,分享的精神是無限的。 一、訊號和中斷 1、訊號基本概念 (1)傳送訊號:產生訊號,有多種傳送訊號的方式【一個程序到另一個程序,核心向用戶,程序向自己】 (2)安裝訊號:設定訊號到來時不再執行預設操作,而是執行自定義的程式碼。

    Linux環境程序通訊(一) 管道有名管道(轉)

    管道是Linux支援的最初Unix IPC形式之一,具有以下特點:管道是半雙工的,資料只能向一個方向流動;需要雙方通訊時,需要建立起兩個管道;只能用於父子程序或者兄弟程序之間(具有親緣關係的程序);單獨構成一種獨立的檔案系統:管道對於管道兩端的程序而言,就是一個檔案,但它不是普通的檔案,它不屬於某種檔案系統,

    linux 核心訊號 使用者態訊號

    Linux  核心中的訊號量使用和使用者態的訊號量使用有所不同, 1、核心訊號量,由核心控制路徑使用。 2、使用者態訊號量分為兩種,一種為POSIX,另一種為 SYSTEM V 核心中訊號量的構成以及使用:核心訊號量的構成 核心訊號量類似於自旋鎖,因為當鎖關閉著時,它不允許

    Android(IPC)進程通訊1:Binder由來?

    模塊 分配 寫入 img roi 核心 足夠 因此 images 完整原文:http://tryenough.com/android-ipc1 Android開發的進程間通訊,整個Android的應用都依賴於binder做底層通信機制。而Linux中提供的進程間通訊方式並沒

    keras之ImageDataGenerator引數用法例項-01

    keras圖片生成器ImageDataGenerator keras.preprocessing.image.ImageDataGenerator(featurewise_center=False,     samplewise_center=False,   &nbs

    程序通訊之Linux C命名管道程式設計

    命名管道 管道(匿名管道)的使用侷限性大,這與管道的實現機制有關。而命名管道(Named Pipe)不僅可在同一臺計算機的任意不同程序之間通訊,而且還可以在跨越一個網路的不同計算機的不同程序之間,支援可靠的、單向或雙向的資料通訊。 命名管道不同於管道之處在於它提供一個路徑

    Spring中@Async用法簡單例項

    Spring中@Async用法 引言: 在Java應用中,絕大多數情況下都是通過同步的方式來實現互動處理的;但是在處理與第三方系統互動的時候,容易造成響應遲緩的情況,之前大部分都是使用多執行緒來完成此類任務,其實,在spring 3.x之後,就已經內建了@Async來完美解決這個問題,本文將完成