2010-01-27 56 views
2

我是線程同步中的新手。我正在閱讀許多條件變量的實現,例如boost :: threads和pthread for win32。我只是用wait/notify/noifyall實現了這個非常簡單的監視器,我想這有很多隱藏的問題,我想從更有經驗的人那裏發現。任何建議?什麼是這個極端簡單的線程監視器實現不安全?

class ConditionVar 
{ 

public : 
    ConditionVar() : semaphore (INVALID_HANDLE_VALUE) , total_waiters (0) 
    { 
     semaphore = ::CreateSemaphoreA (NULL , 0 /* initial count */ , LONG_MAX /* max count */ , NULL); 
    } 

    ~ConditionVar() 
    { 
     ::CloseHandle (semaphore) ;  
    } 


public : 
    template <class P> 
    void Wait (P pred) 
    { 
     while (!pred()) Wait(); 
    } 

public : 

    void Wait (void) 
    { 
     INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters + 1); 
     ::WaitForSingleObject (semaphore , INFINITE); 
    } 

    //! it will notify one waiter 
    void Notify (void) 
    { 
     if (INTERLOCKED_READ_ACQUIRE(&total_waiters)) 
     { 
      Wake (1); 
     } 
    } 

    void NotifyAll (void) 
    { 
     if (INTERLOCKED_READ_ACQUIRE(&total_waiters)) 
     { 
      std::cout << "notifying " << total_waiters ; 
      Wake (total_waiters); 
     } 
    } 

protected : 
    void Wake (int count) 
    { 
     INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters - count); 
     ::ReleaseSemaphore (semaphore , count , NULL); 
    } 

private : 
    HANDLE semaphore; 
    long total_waiters; 
}; 
+0

這使得使用Boost庫? – lsalamon 2010-01-27 16:39:42

+0

嗯,我剛纔複製的INTERLOCKED_READ_ACQUIRE/INTERLOCKED_WRITE_RELEASE宏,讀/使用內存柵欄的櫃檯寫入內存。 – 2010-01-27 16:44:03

+0

@Isalamon:我想他想用Boost.Threads來推出他自己的condvar類,以獲得靈感。 – 2010-01-27 18:10:41

回答

0

如果您使用WinAPI的功能,它可能是更好的使用分別與InterlockedIncrement(...)代替InterlockedDecrement(...)INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters + 1);INTERLOCKED_WRITE_RELEASE(&total_waiters,total_waiters - count);

+0

它只是一個宏...它意味着一個原子操作來增加/減少變量 – 2010-01-27 19:03:17

+0

但它是不必要的複雜。如果你無論如何都與Win32 API綁定,爲什麼不使用在那裏提供的原子操作呢?其他Win32程序員已經熟悉這些程序。 – jalf 2010-01-27 20:20:26

2

我認爲,如果你複製你的情況不好的事情會發生,因爲這兩個副本將使用相同的sempahore。這不一定是壞事,但如果語義不完全清楚,它可能會讓人困惑。

您可以輕鬆地用類似的方法來什麼boost::noncopyable使用(或使用升壓)解決這個問題。

+0

是的!謝謝。 – 2010-01-27 19:07:39

1

我喜歡Boost的實施wait(),因爲它需要一個RAII鎖定對象,以共享條件狀態確保訪問是同步的。 RAII使編寫異常安全的代碼更容易。

我有註釋的示例代碼中發現here

boost::condition_variable cond; 
boost::mutex mut; 
bool data_ready; 

void process_data(); 

void wait_for_data_to_process() 
{ 
    boost::unique_lock<boost::mutex> lock(mut); // Mutex acquired here (RAII). 
    while(!data_ready) // Access to data_ready is sync'ed via mutex 'mut' 
    { 
     // While we are blocking, the mutex is released so 
     // that another thread may acquire it to modify data_ready. 
     cond.wait(lock); 

     // Mutex is acquired again upon exiting cond.wait(lock) 
    } 
    process_data(); 

    // Mutex is released when lock goes out of scope. 
} 
0

(個體經營答案)

我發現了一個很大的錯誤。

條件變量有一個外部鎖...這處理不當。

相關問題