linux中兩種基本的同步方法是訊號量和互斥量。這兩種方法很相似,而且它們可以相互通過對方來實現。
現在有個圖書館,其能容納100人,現在有兩個執行緒a、b,a執行緒執行:往圖書管理進入乙個人,b執行緒:從圖書館出來乙個人。那麼為了使得執行緒a在圖書館滿人的時候進入等待,而不是繼續往圖書館裡進人,使得b執行緒在圖書館沒人的時候等待人進入,我們可以引入訊號量:in out 分別初始化為100和0
。那麼a則可以被表示為a:p(in) //剩餘容量減少一 如果容量為0 則等待 b:p(out) //人數減少1 如果人數為0則阻塞等待
......... //登記進入圖書館的人資訊 ............. //記錄 離開圖書館的人資訊 (隨便一系列操作。)
v(out)//增加訊號量out 表示人數+1 v(in) //增加圖書館剩餘容量+1
通過這樣我們就實現了執行緒的同步。
訊號量作用域上鎖時
訊號量
程序間或執行緒間(linux僅執行緒間)
只要訊號量的value大於0,其他執行緒就可以sem_wait成功,成功後訊號量的value減一。若value值不大於0,則sem_wait阻塞,直到sem_post釋放後value值加一
互斥鎖執行緒間
只要被鎖住,其他任何執行緒都不可以訪問被保護的資源
成功後否則就阻塞
下面介紹用訊號量進行同步。
訊號量概念由荷蘭科學家dijkstra首先提出。訊號量是乙個特殊型別的變數,它可以被增加或者減少。但對其的關鍵訪問被保證是原子操作,即使在乙個多執行緒程式中也是如此。
訊號量有兩種型別:
(1)二進位制訊號量。它只有0和1兩種取值。
(2)計數訊號量。它可以有更大的取值範圍。
如果要用訊號量來保護一段**,使其每次只能被乙個執行執行緒執行,就要用到二進位制訊號量、。
如果要允許有限數目的執行緒執行一段指定的**,就需要用到計數訊號量。
由於計數訊號量並不常用,而且它實際上僅僅是二進位制訊號量的一種擴充套件,這裡之介紹二進位制訊號量。
訊號量函式的名字都以sem_開頭。執行緒中使用的基本函式有4個。
注意,需要包含標頭檔案:
[cpp]view plain
copy
print?
#include
[cpp]view plain
copy
print?
intsem_init(sem_t *sem,
intpshared, unsigned
intvalue);
函式解釋:
sem_init() 初始化乙個定位在 sem 的匿名信號量。value 引數指定訊號量的初始值。
pshared 引數指明訊號量是由程序內線程共享,還是由程序之間共享。如果 pshared 的值為 0,那麼訊號量將被程序內的執行緒共享,並且應該放置在所有執行緒都可見的位址上(如全域性變數,或者堆上動態分配的變數)。
如果 pshared 是非零值,那麼訊號量將在程序之間共享,並且應該定位共享記憶體區域(見 shm_open(3)、mmap(2) 和 shmget(2))。(因為通過 fork(2) 建立的孩子繼承其父親的記憶體對映,因此它也可以見到這個訊號量。)所有可以訪問共享記憶體區域的程序都可以使用sem_post(3)、sem_wait(3) 等等操作訊號量。初始化乙個已經初始的訊號量其結果未定義。
返回值
sem_init() 成功時返回 0;錯誤時,返回 -1,並把 errno 設定為合適的值。
錯誤
einval
value 超過 sem_value_max。
enosys
pshared 非零,但系統還沒有支援程序共享的訊號量。
下面是控制訊號量的兩個函式:
[cpp]view plain
copy
print?
intsem_wait(sem_t * sem);
函式說明
sem_wait函式也是乙個原子操作,它的作用是從訊號量的值減去乙個「1」,但它永遠會先等待該訊號量為乙個非零值才開始做減法。也就是說,如果你對乙個值為2的訊號量呼叫sem_wait(),執行緒將會繼續執行,這訊號量的值將減到1。如果對乙個值為0的訊號量呼叫sem_wait(),這個函式就 會地等待直到有其它執行緒增加了這個值使它不再是0為止。如果有兩個執行緒都在sem_wait()中等待同乙個訊號量變成非零值,那麼當它被第三個執行緒增加 乙個「1」時,等待執行緒中只有乙個能夠對訊號量做減法並繼續執行,另乙個還將處於等待狀態。
返回值所有這些函式在成功時都返回 0;錯誤保持訊號量值沒有更改,-1 被返回,並設定 errno 來指明錯誤。
錯誤eintr
這個呼叫被訊號處理器中斷,
einval
sem 不是乙個有效的訊號量。
[cpp]view plain
copy
print?
intsem_post(sem_t * sem); 說明
sem_post函式的作用是給訊號量的值加上乙個「1」,它是乙個「原子操作」---即同時對同乙個訊號量做加「1」操作的兩個執行緒是不會衝突的;而同 時對同乙個檔案進行讀、加和寫操作的兩個程式就有可能會引起衝突。訊號量的值永遠會正確地加乙個「2」--因為有兩個執行緒試圖改變它。
返回值sem_post() 成功時返回 0;錯誤時,訊號量的值沒有更改,-1 被返回,並設定 errno 來指明錯誤。
錯誤einval
sem 不是乙個有效的訊號量。
eoverflow
訊號量允許的最大值將要被超過。
[cpp]view plain
copy
print?
intsem_destroy (sem_t *sem);
這個函式也使用乙個訊號量指標做引數,歸還自己戰勝的一切資源。在清理訊號量的時候如果還有執行緒在等待它,使用者就會收到乙個錯誤。
與其它的函式一樣,這些函式在成功時都返回「0」。
下面主線程中建立了乙個新執行緒,用來統計輸入的字串中字元的個數。訊號量用來控制兩個執行緒對儲存字串陣列的訪問。
(乙個執行緒用來控制輸入,另乙個執行緒用來控制輸出)
**:[cpp]view plain
copy
print?
#include
#include
#include
#include
#include
#include
//執行緒函式
void
*thread_function(
void
*arg);
sem_t bin_sem;//訊號量物件
#define work_size 1024
char
work_area[work_size];
//工作區
intmain()
//建立新執行緒
res = pthread_create(&a_thread,null,thread_function,null);
if(res)
printf("input some text.enter 'end' to finish\n"
);
while
(strncmp(
"end"
,work_area,3) != 0)
printf("waiting for thread to finish\n"
);
//等待子執行緒結束,收集子執行緒資訊
res = pthread_join(a_thread,&thread_result);
if(res)
printf("thread joined\n"
);
//銷毀訊號量物件
sem_destroy(&bin_sem);
exit(exit_success);
} void
*thread_function(
void
*arg)
pthread_exit(null);//執行緒終止執行
}
執行結果:
執行緒同步之訊號量
什麼是訊號量 linux sem 訊號量是一種特殊的變數,訪問具有原子性,用於解決程序或執行緒間共享資源引發的同步問題。使用者態程序對 sem 訊號量可以有以下兩種操作 等待訊號量 當訊號量值為 0 時,程式等待 當訊號量值大於 0 時,訊號量減 1,程式繼續執行。傳送訊號量 將訊號量值加 1 通過...
Linux 執行緒同步之訊號量同步
linux中兩種基本的同步方法是訊號量和互斥量。這兩種方法很相似,而且它們可以相互通過對方來實現。下面介紹用訊號量進行同步。訊號量概念由荷蘭科學家dijkstra首先提出。訊號量是乙個特殊型別的變數,它可以被增加或者減少。但對其的關鍵訪問被保證是原子操作,即使在乙個多執行緒程式中也是如此。訊號量有兩...
Linux 執行緒同步之訊號量同步
linux中兩種基本的同步方法是訊號量和互斥量。這兩種方法很相似,而且它們可以相互通過對方來實現。下面介紹用訊號量進行同步。訊號量概念由荷蘭科學家dijkstra首先提出。訊號量是乙個特殊型別的變數,它可以被增加或者減少。但對其的關鍵訪問被保證是原子操作,即使在乙個多執行緒程式中也是如此。訊號量有兩...