Linux下的AutoResetEvent的C ++等价物是什么?

时间:2011-11-14 21:15:52

标签: c# .net c++ linux multithreading

The description of AutoResetEvent in MSDN

我正在尝试将在C#中实现的线程池移植到Linux下的C ++中。我不知道我应该使用哪些函数与“AutoResetEvent”具有相似的行为。

7 个答案:

答案 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,信号仅到达该特定线程。