[英]What is the C++ equivalent for AutoResetEvent under Linux?
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的文檔,條件變量和自動重置事件不一樣,並且行為不一樣。
您可以使用POSIX互斥鎖和條件變量輕松地重新實現Win32 API事件對象。
但是上面的一些評論讓我說明了這一點:
條件變量與 Event對象不相似 。 條件變量與事件根本不同,因為它沒有內存或狀態,在某種意義上說,如果在調用pthread_cond_signal
或pthread_cond_broadcast
時沒有任何人在條件變量處被阻塞,則不會發生任何事情,特別是如果線程后來通過pthread_cond_wait
阻塞它會阻塞。
我嘗試繪制一個快速自動重置事件實現:
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_;
};
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的等待/通知機制,但需要互斥鎖才能工作。
條件變量不等同於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(),則會出現死鎖,因為如果沒有人在等待它並且條件變量的狀態仍然是“未設置”,則信號會丟失。
對此要非常小心。
我知道派對可能有點晚了,我沒有關於性能差異的信息,但是使用組合pthread_kill和sigwait可能是一個可行的替代方案,如下所示:
在適當的情況下聲明以下內容:
int sigin;
sigset_t sigset;
以下列方式初始化以前的變量:
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &sigset, null);
在等待線程中,調用sigwait:
sigwait(&sigset, &sigin);
然后,在應該喚醒等待線程的線程上,您可以這樣做:
pthread_kill(p_handle, SIGUSR1);
其中p_handle是您要取消阻止的線程的句柄。
此示例阻止等待線程,直到交付SIGUSR1。 由於使用了pthread_kill,信號只到達該特定線程。
好吧,可能性最像是一個互斥體 - 你有一些呼叫者要使用共享資源,但只允許一個。在互斥鎖的情況下,調用者會嘗試獲取互斥鎖(例如phtread_mutex_lock),做他們的事情,然后釋放(pthread_mutex_unlock),以便其他一些調用者可以進入。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.