linux 多執行緒程式設計 訊號量的使用

2021-05-12 09:51:30 字數 4799 閱讀 7990

訊號是e.w.dijkstra在二十世紀六十年代末設計的一種程式設計架構。dijkstra的模型與鐵路操作有關:假設某段鐵路是單線的,因此一次只允許一列火車通過。訊號將用於同步通過該軌道的火車。火車在進入單一軌道之前必須等待訊號燈變為允許通行的狀態。火車進入軌道後,會改變訊號狀態,防止其他火車進入該軌道。火車離開這段軌道時,必須再次更改訊號的狀態,以便允許其他火車進入軌道。在計算機版本中,訊號以簡單整數來表示。執行緒等待獲得許可以便繼續執行,然後發出訊號,表示該執行緒已經通過針對訊號執行p操作來繼續執行。執行緒必須等到訊號的值為正,然後才能通過將訊號值減1來更改該值。完成此操作後,執行緒會執行v操作,即通過將訊號值加1來更改該值。這些操作必須以原子方式執行,不能再將其劃分成子操作,即,在這些子操作之間不能對訊號執行其他操作。在p操作中,訊號值在減小之前必須為正,從而確保生成的訊號值不為負,並且比該值減小之前小1。在p和v操作中,必須在沒有干擾的情況下進行運算。如果針對同一訊號同時執行兩個v操作,則實際結果是訊號的新值比原來大2。對於大多數人來說,如同記住dijkstra是荷蘭人一樣,記住p和v本身的含義並不重要。但是,真正學術的角度來說,p代表prolagen,這是由proberen te verlagen演變而來的杜撰詞,其意思是嘗試減小。v代表verhogen,其意思是增加。dijkstra的技術說明ewd74中介紹了這些含義。sem_wait(3rt)和sem_post(3rt)分別與dijkstra的p和v操作相對應。sem_trywait(3rt)是p操作的一種條件形式。如果呼叫執行緒不等待就不能減小訊號的值,則該呼叫會立即返回乙個非零值。有兩種基本訊號:二進位制訊號和計數訊號量。二進位制訊號的值只能是0或1,計數訊號量可

以是任意非負值。二進位制訊號在邏輯上相當於乙個互斥鎖。

不過,儘管不會強制,但互斥鎖應當僅由持有該鎖的執行緒來解除鎖定。因為不存在「持有訊號的執行緒」這一概念,所以,任何執行緒都可以執行v或sem_post(3rt)操作。計數訊號量與互斥鎖一起使用時的功能幾乎與條件變數一樣強大。在許多情況下,使用計數訊號量實現的**比使用條件變數實現的**更為簡單。但是,將互斥鎖用於條件變數時,會存在乙個隱含的括號。該括號可以清楚表明程式受保護的部分。對於訊號則不必如此,可以使用併發程式設計當中的go to對其進行呼叫。訊號的功能強大,但是容易以非結構化的不確定方式使用。

1 命名訊號量和未命名訊號量

posix訊號可以是未命名的,也可以是命名的。未命名訊號在程序記憶體中分配,並會進行初始化。未命名訊號可能可供多個程序使用,具體取決於訊號的分配和初始化的方式。未命名訊號可以是通過fork()繼承的專用訊號,也可以通過用來分配和對映這些訊號的常規檔案的訪問保護功能對其進行保護。命名訊號類似於程序共享的訊號,區別在於命名訊號是使用路徑名而非pshared值引用的。命名訊號可以由多個程序共享。命名訊號具有屬主使用者id、組id和保護模式。對於open、retrieve、close和remove命名訊號,可以使用以下函式:sem_open、sem_getvalue、sem_close和sem_unlink。通過使用sem_open,可以建立乙個命名訊號,其名稱是在檔案系統的命名空間中定義的。

2 計數訊號量概述

從概念上來說,訊號量是乙個非負整數計數。訊號量通常用來協調對資源的訪問,其中訊號計數會初始化為可用資源的數目。然後,執行緒在資源增加時會增加計數,在刪除資源時會減小計數,這些操作都以原子方式執行。如果訊號計數變為零,則表明已無可用資源。計數為零時,嘗試減小訊號的執行緒會被阻塞,直到計數大於零為止。

由於訊號無需由同乙個執行緒來獲取和釋放,因此訊號可用於非同步事件通知,如用於訊號處理程式中。同時,由於訊號包含狀態,因此可以非同步方式使用,而不用象條件變數那樣要求獲取互斥鎖。但是,訊號的效率不如互斥鎖高。預設情況下,如果有多個執行緒正在等待訊號,則解除阻塞的順序是不確定的。訊號在使用前必須先初始化,但是訊號沒有屬性。

3 初始化訊號量

使用sem_init(3rt)可以將sem所指示的未命名訊號變數初始化為value。

sem_init語法

int sem_init(sem_t *sem, int pshared, unsigned int value);

#include

sem_t sem;

int pshared;

int ret;

int value;

/* initialize a private semaphore */

pshared =0;

value =1;

ret = sem_init(&sem, pshared, value);

如果pshared的值為零,則不能在程序之間共享訊號。如果pshared的值不為零,則可以在程序之間共享訊號。

注意:

(1)多個執行緒決不能初始化同乙個訊號。

(2)不得對其他執行緒正在使用的訊號重新初始化。

4 初始化程序內訊號量

pshared為0時,訊號只能由該程序內的所有執行緒使用。

#include

sem_t sem;

int ret;

int count = 4;

/* to be used within this process only */

ret = sem_init(&sem, 0, count);

5 初始化程序間訊號量

pshared不為零時,訊號可以由其他程序共享。

#include

sem_t sem;

int ret;

int count = 4;

/* to be shared among processes */

ret = sem_init(&sem, 1, count);

6 sem_init返回值

sem_init()在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函式將失敗並返回對應的值。

einval

描述:引數值超過了sem_value_max。

enospc

描述:初始化訊號所需的資源已經用完。到達訊號的sem_nsems_max限制。

enosys

描述:系統不支援sem_init()函式。

eperm

描述:程序缺少初始化訊號所需的適當許可權。

7 增加訊號

sem_post語法

int sem_post(sem_t *sem);

#include

sem_t sem;

int ret;

ret = sem_post(&sem); /* semaphore is posted */

如果所有執行緒均基於訊號阻塞,則會對其中乙個執行緒解除阻塞。

sem_post返回值

sem_post()在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下情況,該函式將失敗並返回對應的值。

einval

描述: sem所指示的位址非法。

8 基於訊號計數進行阻塞

使用sem_wait(3rt)可以阻塞呼叫執行緒,直到sem所指示的訊號計數大於零為止,之後以原

子方式減小計數。

sem_wait語法

int sem_wait(sem_t *sem);

#include

sem_t sem;

int ret;

ret = sem_wait(&sem); /* wait for semaphore */

sem_wait返回值

sem_wait()在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函式將失敗並返回對應的值。

einval

描述: sem所指示的位址非法。

eintr

描述:此函式已被訊號中斷。

9 減小訊號計數

使用sem_trywait(3rt)可以在計數大於零時,嘗試以原子方式減小sem所指示的訊號計數。

sem_trywait語法

int sem_trywait(sem_t *sem);

#include

sem_t sem;

int ret;

ret = sem_trywait(&sem); /* try to wait for semaphore*/

此函式是sem_wait()的非阻塞版本。sem_trywait()在失敗時會立即返回。

sem_trywait返回值

sem_trywait()在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函式將失敗並返回對應的值。

einval

描述: sem所指示的位址非法。

eintr

描述:此函式已被訊號中斷。

eagain

描述:訊號已為鎖定狀態,因此該訊號不能通過sem_trywait()操作立即鎖定。

10 銷毀訊號狀態

使用sem_destroy(3rt)可以銷毀與sem所指示的未命名訊號相關聯的任何狀態。

sem_destroy語法

int sem_destroy(sem_t *sem);

#include

sem_t sem;

int ret;

ret = sem_destroy(&sem); /* the semaphore is destroyed */

sem_destroy返回值

sem_destroy()在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以

下情況,該函式將失敗並返回對應的值。

einval

描述: sem所指示的位址非法。

Linux多執行緒程式設計 訊號量

1.1訊號量簡介 linux下主要分為兩種訊號量,system v和posix訊號量,posix訊號量又分為無名訊號量和有名訊號量,這裡我們只分享無名訊號量這裡我們主要研究posix訊號量。訊號量是同步的一種方式,常常用於對共享資源的訪問,舉乙個常見的例子,假如乙個停車場有100個停車位,我們將車停...

C多執行緒程式設計 訊號量

這是對由sem指定的訊號量進行初始化,設定好它的共享選項 linux 只支援為0,即表示它是當前程序的區域性訊號量 然後給它乙個初始值value。int sem init sem t sem int pshared,unsigned int value 給訊號量減1,然後等待直到訊號量的值大於0。i...

多執行緒 訊號量

訊號量 semaphore類 建立帶指定許可數的訊號量 semaphore semaphore new semaphore 1 建立乙個許可的訊號量 訊號量用來限制訪問共享數資源的執行緒數。在訪問資源之前,執行緒必須從訊號量獲取許可,在訪問完資源後釋放訊號量。任務通過呼叫訊號量的acquire 方法...