程序間通訊 IPC 主題二之 訊號量

2021-08-02 12:59:23 字數 4369 閱讀 4993

訊號量的本質是一種資料操作鎖,它本身不具有資料交換的功能,而是通過控制其他的通訊資源(檔案,外部裝置)來實現程序間通訊,它本身只是一種外部資源的標識,訊號量在此過程中負責資料操作的互斥,同步等功能。

一:為什麼要使用訊號量

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

訊號量是乙個特殊的變數,程式對其訪問都是原子操作,且只允許對它進行等待(即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中。

注:訊號量的意圖在於程序間同步,互斥鎖和條件變數的意圖在於執行緒間同步,但是訊號量也可用於執行緒間,互斥鎖和條件變數也可用於程序間。

函式:

訊號量函式由semget、semop、semctl三個函式組成。

semget : 作用是建立乙個新訊號量或取得乙個已有訊號量。

函式原型:int semget(key_t key, int num_sems, int sem_flags);

引數 key:訊號量集識別符號(成功返回非零唯一標識碼,失敗返回 -1)。

num_sems : 指定需要的訊號量數目, 一般情況下為1。

sem_flags

ipc_creat : 當想要當訊號量不存在時建立乙個新的訊號量。

ipc_creat | ipc_excl : 建立乙個新的唯一的訊號量,如果訊號量已存在,返回乙個錯誤。

semop : 作用是改變訊號量的值。

函式原型:

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

引數 sem_id : semget成功返回的訊號標識碼。

sembuf結構:

01

struct sembuf;

num_sem_ops : 進行操作訊號量的個數,即sembuf結構變數的個數,需大於或等於1。最常見設定此值等於1,只完成對乙個訊號量的操作。

semctl : 該函式用來直接控制訊號量資訊。

函式原型:

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

引數 sem_id : 訊號量集識別符號。

sem_num : 指定需要的訊號量數目, 一般情況下為1。

commond:有以下兩種可能

(1)setval:用來把訊號量初始化為乙個已知的值。這個值通過union semun中的val成員設定,其作用是在訊號量第一次使用前對它進行設定。

(2)ipc_rmid:用於刪除乙個已經無需繼續使用的訊號量識別符號。

下面我們來用**測試一下使用訊號量進行程序間通訊。

首先是未加訊號量的父子程序:

1

#include "comm.h"

2int main()

3 10else

if(0 == id)

11

22 }

23else

24

36 pid_t ret = waitpid(id, null, 0);

37if(ret > 0)

38

41 }

42return

0; 43 }

執行結果:

可以看出父子程序隨機向螢幕上輸出字元,這些字元毫無順序,所以證明這一操作並不是原子的。

接下來是加了訊號量的**:

1

#ifndef _comm_h_

2#define _conn_h_

3#include

4#include

5#include

6#include

7#include

8#include 910

#define pathname "."

11#define proj_id 0

1213

union semun

14 ;

2021

int creatsems(int nums);

22int getsem();//獲取訊號量

23int destorysems(int semid);

24int initsems(int semid, int which, int value);

25int p(int semid, int which);

26int v(int semid, int which);

2728

#endif

comm.c

1

#include "comm.h"

2static

int commsems(int nsems, int semflag)

3 10int semid = semget(_key, nsems, semflag);

11if(semid < 0)

12

16return semid;

17 }

1819

int creatsems(int nums)

20 2324

//將semid對應的訊號量集中下標為which的訊號量初始化value

25int initsems(int semid, int which, int

value)

26 35return

0; 36 }

3738

static

int commsemop(int semid, int which, int op)

39 4647

int p(int semid, int which)

48 5152

int v(int semid, int which)

53 5657

int getsems()

58 6162

int destorysems(int semid)

63 69return

0; 70 }

test_sem.c

1

#include "comm.h"

2int main()

3 23 }

24else

25

3940 pid_t ret = waitpid(id, null, 0);

41if(ret > 0)

42

45 }

46return

0; 47 }

執行結果:

通過執行結果可以清晰的看到父子程序每次輸出的兩個字元都是同時輸出的,並沒有像之前那樣雜亂無章,這也正說明了訊號量使得兩個程序之間的通訊保持原子性。

程序間通訊(IPC)之 訊號量

一.訊號量 在談論訊號量之前,先要提到臨界資源和臨界區的概念,臨界資源是指多個程序訪問但乙個時間段內只允許乙個程序獨佔的資源,而臨界區是指多個程序訪問臨界資源的這一段公共的 訊號量的本質是一種資料操作鎖,也可以說就是乙個計數器,它本身並不能提供對程序間的通訊,而是通過控制某一資源來完成程序間的互斥和...

程序間通訊IPC 訊號量

訊號量 訊號量 主要來實現程序間或執行緒間的同步 也可以實現互斥 訊號量的值 表示資源的可用量。訊號量操作流程 1 建立乙個訊號量集合 param 2 訊號量集合中訊號量的個數 int semid int semget key t key,int nsems,int sem semid semget...

IPC程序間通訊(訊號量)

訊號量是乙個計數器,用於為多個程序提供對共享資料物件的訪問。訊號量和p v原語操作是由dijkstra 迪傑斯特拉 所提出的。執行p操作時,將該程序狀態設定為等待狀態,並把 該程序的pcb插入相應的等待佇列s.queue末尾 執行v操作時,喚醒相應等待佇列s.queue中等待的乙個程序 改變其狀態為...