2011-07-23 139 views
11

我需要兩個線程進行「tick tock」模式。當用旗語implmented這看起來不錯:使用互斥量作爲信號量?

Semaphore tick_sem(1); 
Semaphore tock_sem(0); 

void ticker(void) 
{ 
    while(true) 
    { 
     P(tick_sem); 
     do_tick(); 
     V(tock_sem); 
    } 
} 

void tocker(void) 
{ 
    while(true) 
    { 
     P(tock_sem); 
     do_tock(); 
     V(tick_sem); 
    } 
} 

但是,如果我做同樣的事情用一個互斥體(這在技術上是一個二進制信號),它有一個奇怪的碼味。

std::mutex tick_mutex; 
std::mutex tock_mutex; 
tock_mutex.lock(); 

void ticker(void) 
{ 
    while(true) 
    { 
     tick_mutex.lock(); 
     do_tick(); 
     tock_mutex.unlock(); 
    } 
} 

void tocker(void) 
{ 
    while(true) 
    { 
     tock_mutex.lock() 
     do_tock(); 
     tick_mutex.unlock(); 
    } 
} 

我覺得味道是一個互斥體並不意味着將信息傳遞給另一個線程。 (C++ 11標準委員會增加了一個錯誤的try_lock來阻止意外的信息傳輸;第30.4.1/14節)似乎互斥鎖是爲了同步對變量的訪問,然後該變量可以將信息傳遞給另一個線程。

最後,當執行std::condition_variable時,它看起來是正確的,但它更復雜(一個tick_vs_tock變量,一個互斥量和一個條件變量)。爲了簡潔,我省略了實現,但它非常簡單。

互斥體解決方案是否正確?或者是有一些微妙的錯誤呢?

有沒有一個很好的模式來解決我沒有想到的tick/tock問題?

+0

順便說一句:這個問題的出現只是因爲C++ 0x沒有'std :: semaphore',雙std :: mutex'解決方案比'std :: condition_variable'解決方案更簡單。 –

+3

(爲什麼)在當前不存在的線程中解鎖()一個互斥鎖是否有效? –

+0

@Steve這真的是一個很好的問題(提示,提示,微調,微調)。 –

回答

10

Mutex不僅僅是一個二進制信號量,它也有限制,只有鎖定線程被允許解鎖它。

你打破了這個規則。

編輯:

MSDN

如果調用線程不擁有 互斥對象的ReleaseMutex功能失效。

從一些網站,谷歌打開了爲pthread_mutex_unlock

EPERM當前線程不擁有互斥:如果

的調用pthread_mutex_unlock()函數可能會失敗。

而你會在其他互斥體實現中找到相同的結果。這是有道理的,因爲互斥體應該防止線程訪問資源,所以另一個線程不應該能夠解鎖它。

+0

按照Steve的評論。這真的是一個規則嗎?這絕對是一個好主意。 –

+0

@deft - 我認爲這取決於互斥體的實現,這是依賴於系統的。即使系統允許,解鎖其他人的互斥鎖通常也不是一個好主意。 – littleadv

+0

@deft_code:我還沒有讀過FDIS的互斥部分,但如果*不是*規則,我會感到驚訝。互斥鎖擁有一個所有者,這是它們作爲同步工具基本定義的一部分。 –

9

由於您有案例使用信號量,我認爲該修復程序是可移植的implement one using a mutex and a condition variable

這可能不是特別有效(因爲它將使用每個信號量的互斥量/ condvar對),但是您可以在具有自己的信號量(如Posix和Windows)的系統上切換備用實現。

顯然semaphores are "too error-prone"。對於Boost的所有應有的尊重,我認爲至少我們中的一些人可以管理。當然,你可以打結trying to do complicated things with multiple semaphores,他們是一個非常低級的工具。但是當他們是正確的時候,沒問題。

+0

我同意「太容易出錯」的東西很奇怪。互斥體也可能會出錯。所以可以一個錘子。 – asveikau