The description of AutoResetEvent in MSDN
我正在尝试将在C#中实现的线程池移植到Linux下的C ++中。我不知道我应该使用哪些函数与“AutoResetEvent”具有相似的行为。
答案 0 :(得分: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的文档,条件变量和自动重置事件是不一样的,并且行为不一样。
答案 1 :(得分:3)
我很确定你正在寻找条件变量。对另一个SO问题的接受答案:Condition variables in C# - 似乎证实了这一点。
参见例如有关POSIX线程中条件变量的详细信息,请this tutorial。
答案 2 :(得分:2)
您可以使用POSIX互斥锁和条件变量轻松地重新实现Win32 API事件对象。
然而,上面的一些评论让我说明了这一点:
条件变量与Event对象不相似。条件变量基本与事件的不同之处在于它没有内存或状态,在某种意义上,如果在调用{{1}时条件变量中没有任何人被阻塞}或pthread_cond_signal
什么都不会发生,特别是如果一个线程稍后通过pthread_cond_broadcast
来阻止它将阻止。
我尝试绘制一个快速自动重置事件实现:
pthread_cond_wait
答案 3 :(得分:1)
条件变量 NOT 相当于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(),则会出现死锁,因为如果没有人在等待它并且条件变量的状态仍然是“未设置”,则信号会丢失。
要非常小心。
答案 4 :(得分: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的等待/通知机制,但需要互斥锁才能工作。
答案 5 :(得分:0)
好吧,可能性最像是一个互斥体 - 你有一些呼叫者要使用共享资源,但只允许一个。在互斥锁的情况下,调用者会尝试获取互斥锁(例如phtread_mutex_lock),做他们的事情,然后释放(pthread_mutex_unlock),以便其他一些调用者可以进入。
答案 6 :(得分:0)
我知道这可能会晚一些,并且我没有关于性能差异的信息,但是使用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,信号仅到达该特定线程。