2011-11-14 67 views

回答

11

的的AutoResetEvent是最類似於一個二進制信號。說「條件變量」的人本身並沒有錯,但條件變量在相似的情況下使用,而不是類似的對象。您可以實現條件變量之上的(未命名)的AutoResetEvent:

#include <pthread.h> 
#include <stdio.h> 

class AutoResetEvent 
{ 
    public: 
    explicit AutoResetEvent(bool initial = false); 

    ~AutoResetEvent(); 
    void Set(); 
    void Reset(); 

    bool WaitOne(); 

    private: 
    AutoResetEvent(const AutoResetEvent&); 
    AutoResetEvent& operator=(const AutoResetEvent&); // non-copyable 
    bool flag_; 
    pthread_mutex_t protect_; 
    pthread_cond_t signal_; 
}; 

AutoResetEvent::AutoResetEvent(bool initial) 
: flag_(initial) 
{ 
    pthread_mutex_init(&protect_, NULL); 
    pthread_cond_init(&signal_, NULL); 
} 

void AutoResetEvent::Set() 
{ 
    pthread_mutex_lock(&protect_); 
    flag_ = true; 
    pthread_mutex_unlock(&protect_); 
    pthread_cond_signal(&signal_); 
} 

void AutoResetEvent::Reset() 
{ 
    pthread_mutex_lock(&protect_); 
    flag_ = false; 
    pthread_mutex_unlock(&protect_); 
} 

bool AutoResetEvent::WaitOne() 
{ 
    pthread_mutex_lock(&protect_); 
    while(!flag_) // prevent spurious wakeups from doing harm 
    pthread_cond_wait(&signal_, &protect_); 
    flag_ = false; // waiting resets the flag 
    pthread_mutex_unlock(&protect_); 
    return true; 
} 

AutoResetEvent::~AutoResetEvent() 
{ 
    pthread_mutex_destroy(&protect_); 
    pthread_cond_destroy(&signal_); 
} 


AutoResetEvent event; 

void *otherthread(void *) 
{ 
    event.WaitOne(); 
    printf("Hello from other thread!\n"); 
    return NULL; 
} 


int main() 
{ 
    pthread_t h; 
    pthread_create(&h, NULL, &otherthread, NULL); 
    printf("Hello from the first thread\n"); 
    event.Set(); 

    pthread_join(h, NULL); 
    return 0; 
} 

但是,如果你需要一個名爲自動復位的事件,你可能會想看看信號燈,並可能有一個稍微困難的時候翻譯你的代碼。無論哪種方式,我會仔細看看你的平臺上的pthreads的文檔,條件變量和自動重置事件是不一樣的,並且行爲不一樣。

0

好吧,它最像是一個互斥體 - 你有一些調用者用於共享資源,但只允許一個調用。在互斥體情況下,調用者會嘗試獲取互斥體(例如phtread_mutex_lock) ,做好自己的事情,然後鬆開(調用pthread_mutex_unlock),以便其他一些來電者就可以得到。

+1

不,它根本不像一個互斥體。這更像是一個條件變量。 – Gabe

3

我敢肯定你要找的條件變量。對其他SO問題的接受答案:Condition variables in C# - 似乎證實了這一點。

參見例如有關POSIX線程中條件變量的詳細信息,請參閱this tutorial

+1

微軟喜歡將「庫」,「平臺」和「語言」之間的差異模糊爲一個強迫你「購買微軟」的大混亂。事實上,.Net中的「AutoResetEvent」類是Win32中的「Event」原語的封裝,類似於PThread中的「條件變量」。學習Linux的PThreads。除了Linux之外,PThread還可以用於其他平臺上,除了C++之外,還可以與其他語言(C,Python等)一起使用。 – paulsm4

+0

只是想知道,使用boost:線程庫實現它會更容易嗎? – derekhh

+0

@derekhh:我不知道「更容易」,條件變量是一個相當簡單的構造,但是如果你已經使用boost :: thread(IMO是一個非常好的選擇),通過一切手段使用它的條件變量它將適合您的代碼的其餘部分:http://www.boost.org/doc/libs/1_47_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref –

2

您可以輕鬆地重新實現使用POSIX互斥和條件變量的Win32 API的事件對象。

但是一些評論上面讓我說明這一點:

條件變量是沒有類似一個事件對象。條件變量是根本從事件,因爲它沒有記憶或狀態,在這個意義上,如果沒有人擋在當時調用條件變量pthread_cond_signalpthread_cond_broadcast什麼都不會發生,特別是不同的如果一個線程後來通過pthread_cond_wait來阻止它將阻止塊。

I'l嘗試繪製一個快速的自動重置事件的實現:

class event 
{ 
public: 
    event(): signalled_ (false) {} 

    void signal() 
    { 
    std::unique_lock<std::mutex> lock(mutex_); 
    signalled_ = true; 
    cond_.notify_one(); 
    } 

    void wait() 
    { 
    std::unique_lock<std::mutex> lock(mutex_); 

    while (!signalled_) 
     cond_.wait (lock); 
    signalled_ = false; 
    } 

protected: 
    std::mutex mutex_; 
    std::condition_variable cond_; 
    bool signalled_; 
}; 
1

條件變量的AutoResetEvent的等價物。他們相當於顯示器。所不同的是關鍵的,並且如果不正確使用會導致死鎖:

在C#程序想象兩個線程A和B. A調用WaitOne()和B調用Set()。如果B在A到達對WaitOne()的調用之前執行Set(),則沒有問題,因爲Set()發送給AutoResetEvent()的信號是持久的,並且它將保持設置狀態直到執行WaitOne()。

現在,在C,想像兩個線程C和D. C調用wait()的,d調用notify()。如果C在D調用notify()時已經在等待一切正常。如果C在D調用notify()之前沒有設法達到wait(),那麼會發生死鎖,因爲如果沒有人等待它,並且條件變量的狀態仍「未設置」,則信號丟失。

請注意這一點。

1

從Boost的主題/條件文檔的例子是非常相似的正常的ManualResetEvent和的AutoResetEvent用法: http://www.boost.org/doc/libs/1_53_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
(我做了清晰一些小的修改)

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

void wait_for_data_to_process() 
{ 
    boost::unique_lock<boost::mutex> lock(mut); 
    while(!data_ready) 
    { 
     cond.wait(lock); 
    } 
} 

void prepare_data_for_processing() 
{ 
    { //scope for lock_guard 
     boost::lock_guard<boost::mutex> lock(mut); 
     data_ready=true; 
    } 
    cond.notify_one(); 
} 

注意條件提供AutoResetEvent和ManualResetEvent的等待/通知機制,但需要互斥體才能工作。

相關問題