Linux下的AutoResetEvent在c++中的等效函数是什么?
本文关键字:函数 是什么 下的 AutoResetEvent c++ Linux | 更新日期: 2023-09-27 18:14:41
MSDN中AutoResetEvent的描述
我试图在Linux下将c#实现的线程池移植到c++。我不知道我应该使用哪些函数有类似的行为"AutoResetEvent"
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文档,条件变量和自动重置事件不相同,行为也不相同。
我很确定你正在寻找条件变量。另一个SO问题的公认答案是:c#中的条件变量——似乎证实了这一点。
关于POSIX线程中条件变量的详细信息,请参见本教程。条件变量NOT相当于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(),则会出现死锁,因为如果没有人在等待信号并且条件变量的状态仍然为"未设置",则信号丢失。
对此要非常小心。
您可以使用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的等待/通知机制,但需要互斥锁才能工作。
嗯,它最像一个互斥锁——你有很多调用者去共享资源,但只允许一个调用者进入。在互斥锁的情况下,调用者会尝试获得互斥锁(例如phtread_mutex_lock),做他们的事情,然后释放(pthread_mutex_unlock),以便其他调用者可以进入。
我知道这可能有点晚了,我没有关于性能差异的信息,但是组合使用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,所以信号只能到达特定的线程。