2016-06-13 58 views
2

我開始懷疑信號量的概念;請閱讀以及理解我的問題......確保這個生產者 - 消費者示例不會死鎖的條件?

根據手冊,sem_post將當信號量的值大於0更大解鎖線程...所以,如果我有這樣的代碼:

void* producer(void* arg) 
{ 
    while(1) 
    { 
     sem_wait(&sem_produce); 
     sem_wait(&mutex); 
     // Insert item into buffer 
     sem_post(&mutex); 
     sem_post(&sem_consume); 
    } 
    pthread_exit(NULL); 
} 

void* consumer(void* arg) 
{ 
    while(1) 
    { 
     sem_wait(&sem_consume); 
     sem_wait(&mutex); 
     // Remove item from buffer 
     sem_post(&mutex); 
     sem_post(&sem_produce); 
    } 
    pthread_exit(NULL); 
} 

在哪裏sem_consume0的值初始化,sem_produceN初始化。

如果例如N消費者在生產者之前運行並嘗試消費會發生什麼?那麼sem_consume應該有-N的值,如果接下來有N插入,sem_consumesem_produce都應該是0,或者我錯了嗎?那麼這意味着消費者將被卡住,因爲(根據手冊)sem_post將在信號量的值變得大於零時解鎖線程...

因此,根據我從手冊中瞭解並考慮上述示例,只有這種方式才能正常工作,如果sem_consume永遠不會達到-N的價值。

我是對的?如果是的話,我該如何改進這個例子以免卡住?如果答案是否定的,我錯了什麼?

+2

「那麼sem_consume應具有-N的值」。那永遠不會發生。它寫在整個信號手冊上。 [sem_overview manual](http://man7.org/linux/man-pages/man7/sem_overview.7.html)說:「一個信號量是一個整數,它的值**永遠不會低於零**」。 [sem_wait](http://man7.org/linux/man-pages/man3/sem_wait.3.html):「如果信號量當前的值爲零,則調用將阻塞,直到可以執行遞減(即信號量值高於零)或信號處理程序中斷呼叫。「 – kaylum

+0

如果消費者在生產者之前運行,那麼消費者都將等待'sem_consume',直到生產者設法執行'sem_post(&sem_consume)',對嗎?只有一個消費者會爲每個'sem_post(&sem_consume)'運行。在生產者被阻止等待消費者消費之前,會有'N'個項目排隊。 –

+0

奇怪的是,在我的並行編程課程中,我認爲我從老師那裏聽說,信號量的值可能是負值,並且這個負值將表示阻塞線程的數量,如果此值不能爲負,那麼我沒有疑惑。 – OiciTrap

回答

0

所以,從我從手動理解和考慮上述 例如,僅此程序將正常工作的方法是,如果sem_consume 永遠達不到-N的值。

這是正確的,信號量只是平坦不允許是一個負值的時期。正如在評論中指出了很多人,旗語手冊明確說明這一點:

A semaphore is an integer whose value is never allowed to fall below zero.

而且這樣的:

If the semaphore currently has the value zero, then the call blocks until either it becomes possible to perform the decrement (i.e., the semaphore value rises above zero), or a signal handler interrupts the call.

而且這樣的:

Decrementing is a (possibly) blocking function. If the resulting semaphore value is negative, the calling thread or process is blocked, and cannot continue until some other thread or process increments it.

從本質上講,信號量的整點是積極的僅是,當一個進程嘗試它遞減爲負,這一過程被暫停,直到另一個進程增加它足夠它不成爲負當原始進程被允許遞減時。

爲了您的評論:

這是奇怪的,在我的並行編程過程中,我想我從老師那一個信號量的值可以是負值,這負值將代表阻塞的線程數聽說,如果這個值不能爲負,那麼我毫不懷疑。

這基本上是發生了什麼,但你不能查看這個值。如果你試圖抓取一個當前不是正的信號量,那麼試圖抓住它的函數會被阻塞,直到它再次變爲正值。

0

我認爲sem_post和sem_wait的定義如下。

sem_wait() 將信號量的值減1,如果該值爲負,則等待。

sem_post() 將信號量的值遞增1,如果有一個或多個線程在等待,則喚醒一個。

因此,sem_post()並不真正檢查值是否大於0。另外,如果sem_post()真的檢查,那麼信號量永遠不能用作鎖。請參閱下面的代碼片段。

sem_t m; 
sem_init(&m, 0, 1) 

sem_wait(&m) 
... critical section... 
sem_post(&m) 

比方說,線程1先被調度,然後遞減值爲0並進入臨界區。在完成之前,其他三個線程會一個接一個地調度,並且每個線程都會進一步減少信號量和塊。現在,線程1再次被調度,完成關鍵部分並調用sem_post()。我的觀點是,如果它確實檢查了一個正值,那麼其他線程將永遠不會被安排,事實並非如此。請讓我知道這是否回答你的問題。

謝謝。