简体   繁体   English

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

[英]What is the C++ equivalent for AutoResetEvent under Linux?

The description of AutoResetEvent in MSDN MSDN中AutoResetEvent的说明

I'm trying to port a Thread Pool implemented in C# to C++ under Linux. 我正在尝试将在C#中实现的线程池移植到Linux下的C ++中。 I don't know which functions I should use that have similar behaviors to "AutoResetEvent". 我不知道我应该使用哪些功能与“AutoResetEvent”具有相似的行为。

An AutoResetEvent is most akin to a binary semaphore. AutoResetEvent最类似于二进制信号量。 People saying "conditional variables" aren't wrong per se, but condition variables are used in similar situations, rather than being similar objects. 人们说“条件变量”本身并没有错,但条件变量在类似的情况下使用,而不是类似的对象。 You can implement an (unnamed) AutoResetEvent on top of condition variables: 您可以在条件变量之上实现(未命名)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;
}

If however, you need named auto reset events, you'll likely want to look at semaphores, and may have a slightly more difficult time translating your code. 但是,如果您需要命名自动重置事件,则可能需要查看信号量,并且可能需要稍微更难以翻译代码。 Either way I would look careful at the documentation for pthreads on your platform, condition variables and auto reset events are not the same and do not behave the same. 无论哪种方式,我都会仔细查看平台上pthreads的文档,条件变量和自动重置事件不一样,并且行为不一样。

I'm pretty sure you're looking for condition variables. 我很确定你在寻找条件变量。 The accepted answer to this other SO question: Condition variables in C# -- seems to confirm it. 对于另一个SO问题的接受答案: C#中的条件变量 - 似乎证实了这一点。

See eg this tutorial for details on condition variables in POSIX threads. 有关POSIX线程中条件变量的详细信息,请参阅本教程

You can easily re-implement Win32 API Event objects using POSIX mutexes and condition variables. 您可以使用POSIX互斥锁和条件变量轻松地重新实现Win32 API事件对象。

However some of the comments above make me state this: 但是上面的一些评论让我说明了这一点:

A condition variable is not analogous to an Event object. 条件变量 Event对象不相似 A condition variable is fundamentally different from an Event in that it does not have memory or state, in the sense that if there isn't anyone blocked at the condition variable at the time you call pthread_cond_signal or pthread_cond_broadcast nothing will happen, in particular if a thread comes later to block via pthread_cond_wait it will block. 条件变量与事件根本不同,因为它没有内存或状态,在某种意义上说,如果在调用pthread_cond_signalpthread_cond_broadcast时没有任何人在条件变量处被阻塞,则不会发生任何事情,特别是如果线程后来通过pthread_cond_wait阻塞它阻塞。

I'l try to sketch a quick auto-reset event implementation: 我尝试绘制一个快速自动重置事件实现:

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_;
};

The example from Boost's Thread/Condition documentation is pretty similar to the normal ManualResetEvent and AutoResetEvent usage: http://www.boost.org/doc/libs/1_53_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref Boost的线程/条件文档中的示例非常类似于正常的ManualResetEvent和AutoResetEvent用法: http//www.boost.org/doc/libs/1_53_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
(I've made some small edits for clarity) (为清楚起见,我做了一些小编辑)

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();
}

Note that conditions provide the wait/notify mechanism of AutoResetEvent and ManualResetEvent but require a mutex to work. 请注意,条件提供AutoResetEvent和ManualResetEvent的等待/通知机制,但需要互斥锁才能工作。

Conditional variables are NOT the equivalent of AutoResetEvent. 条件变量等同于AutoResetEvent。 They are the equivalent of Monitors. 它们相当于监视器。 The difference is critical and may cause deadlocks if not used properly: 差异很严重,如果使用不当可能会导致死锁:

Imagine two threads A and B in a C# program. 想象一下C#程序中的两个线程A和B. A calls WaitOne() and B calls Set(). A调用WaitOne()和B调用Set()。 If B executes Set() before A reaches the call to WaitOne(), there is no problem because the signal sent to the AutoResetEvent() by Set() is persistent and it will remain set until a WaitOne() is executed. 如果B在A到达对WaitOne()的调用之前执行Set(),则没有问题,因为Set()发送到AutoResetEvent()的信号是持久的,并且它将保持设置直到执行WaitOne()。

Now in C, imagine two threads C and D. C calls wait(), D calls notify(). 现在在C中,想象两个线程C和D.C调用wait(),D调用notify()。 If C is waiting already when D calls notify() everything is ok. 如果C正在等待D调用notify(),一切正常。 If C did not manage to reach wait() before D calls notify(), you have a deadlock because the signal is lost if nobody is waiting on it and the status of the conditional variable is still "unset". 如果C在D调用notify()之前没有设法到达wait(),则会出现死锁,因为如果没有人在等待它并且条件变量的状态仍然是“未设置”,则信号会丢失。

Be very careful about this. 对此要非常小心。

I know this may be a little late to the party and I have no information about the performance differences, but it might be a viable alternative to use a combination pthread_kill and sigwait, like so: 我知道派对可能有点晚了,我没有关于性能差异的信息,但是使用组合pthread_kill和sigwait可能是一个可行的替代方案,如下所示:

Declare the following, where appropriate: 在适当的情况下声明以下内容:

int sigin;
sigset_t sigset;

initialize the previous variables in the following way: 以下列方式初始化以前的变量:

sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &sigset, null);

in the waiting thread, call sigwait: 在等待线程中,调用sigwait:

sigwait(&sigset, &sigin);

Then, on the thread that is supposed to wake the waiting thread, you could do this: 然后,在应该唤醒等待线程的线程上,您可以这样做:

pthread_kill(p_handle, SIGUSR1);

where p_handle is the handle to the thread you wish to unblock. 其中p_handle是您要取消阻止的线程的句柄。

This example blocks the waiting thread until SIGUSR1 is delivered. 此示例阻止等待线程,直到交付SIGUSR1。 The signal only reaches that specific thread because of using pthread_kill. 由于使用了pthread_kill,信号只到达该特定线程。

好吧,可能性最像是一个互斥体 - 你有一些呼叫者要使用共享资源,但只允许一个。在互斥锁的情况下,调用者会尝试获取互斥锁(例如phtread_mutex_lock),做他们的事情,然后释放(pthread_mutex_unlock),以便其他一些调用者可以进入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM