Linux 下 AutoResetEvent 的 C++ 等价物是啥?
Posted
技术标签:
【中文标题】Linux 下 AutoResetEvent 的 C++ 等价物是啥?【英文标题】:What is the C++ equivalent for AutoResetEvent under Linux?Linux 下 AutoResetEvent 的 C++ 等价物是什么? 【发布时间】:2011-11-14 21:15:52 【问题描述】:The description of AutoResetEvent in MSDN
我正在尝试将在 C# 中实现的线程池移植到 Linux 下的 C++。我不知道应该使用哪些功能与“AutoResetEvent”具有相似的行为。
【问题讨论】:
【参考方案1】: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;
但是,如果您需要命名的自动重置事件,您可能希望查看信号量,并且翻译代码可能会稍微困难一些。无论哪种方式,我都会仔细查看您平台上的 pthread 文档,条件变量和自动重置事件不一样,并且行为也不一样。
【讨论】:
【参考方案2】:我很确定您正在寻找条件变量。这个其他 SO 问题的公认答案:Condition variables in C# -- 似乎证实了这一点。
参见例如this tutorial 了解 POSIX 线程中条件变量的详细信息。
【讨论】:
Microsoft 喜欢将“库”、“平台”和“语言”之间的区别模糊成一个大混乱,迫使您“购买 Microsoft”。事实上,.Net 中的“AutoResetEvent”类是 Win32 中“Event”原语的包装,类似于 PThreads 中的“条件变量”。学习 Linux 的 PThreads。 PThreads 可以在 Linux 之外的其他平台上使用,也可以在 C++ 之外的其他语言(C、Python 等)上使用。 只是想知道,使用 boost:thread 库实现它会更容易吗? @derekhh:我不知道“更简单”,条件变量是一个相当简单的构造,但如果你已经在使用 boost::thread(IMO 是一个非常好的选择),一定要使用它的条件变量包装器,它会适合你的其余代码:boost.org/doc/libs/1_47_0/doc/html/thread/…【参考方案3】:条件变量不等同于 AutoResetEvent。它们相当于监视器。区别很关键,如果使用不当可能会导致死锁:
想象一个 C# 程序中有两个线程 A 和 B。 A 调用 WaitOne(),B 调用 Set()。如果 B 在 A 到达 WaitOne() 调用之前执行 Set(),则没有问题,因为 Set() 发送给 AutoResetEvent() 的信号是持久的,并且在执行 WaitOne() 之前它将保持设置。
现在在 C 中,想象两个线程 C 和 D。C 调用 wait(),D 调用 notify()。如果 D 调用 notify() 时 C 已经在等待,则一切正常。如果 C 在 D 调用 notify() 之前没有设法到达 wait(),那么您就会出现死锁,因为如果没有人在等待信号并且条件变量的状态仍然“未设置”,则信号将丢失。
对此要非常小心。
【讨论】:
【参考方案4】:您可以使用 POSIX 互斥锁和条件变量轻松地重新实现 Win32 API 事件对象。
但是上面的一些 cmets 让我这样说:
条件变量与事件对象不相似。条件变量从根本上不同于事件,因为它没有内存或状态,从某种意义上说,如果在您调用 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_;
;
【讨论】:
【参考方案5】:Boost 的 Thread/Condition 文档中的示例与正常的 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 的等待/通知机制,但需要互斥体才能工作。
【讨论】:
【参考方案6】:嗯,很可能它最像互斥锁 - 您有许多调用者想要共享资源,但只有一个被允许进入。在互斥锁的情况下,调用者会尝试获取互斥锁(例如 phtread_mutex_lock),做他们的事,然后释放 (pthread_mutex_unlock) 以便其他调用者可以进入。
【讨论】:
不,它一点也不像互斥锁。它更像是一个条件变量。【参考方案7】:我知道这可能有点晚了,而且我没有关于性能差异的信息,但使用 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,信号仅到达该特定线程。
【讨论】:
以上是关于Linux 下 AutoResetEvent 的 C++ 等价物是啥?的主要内容,如果未能解决你的问题,请参考以下文章
C#多线程 - 出了啥问题,如何使用 AutoResetEvent
C#各种同步方法 lock, Monitor,Mutex, Semaphore, Interlocked, ReaderWriterLock,AutoResetEvent, ManualResetEv