7

I understand I've asked this question before: What is the C++ equivalent for AutoResetEvent under Linux?

However, I'm learning that in C++0x, the threading library are made much simpler, so I want to pose this question out again, is there an easy way to implement AutoResetEvent in C++0x?

Community
  • 1
  • 1
derekhh
  • 5,272
  • 11
  • 40
  • 60

1 Answers1

18

Here is a translation of the accepted answer to your first question to use C++11 tools:

#include <mutex>
#include <condition_variable>
#include <thread>
#include <stdio.h>

class AutoResetEvent
{
  public:
  explicit AutoResetEvent(bool initial = false);

  void Set();
  void Reset();

  bool WaitOne();

  private:
  AutoResetEvent(const AutoResetEvent&);
  AutoResetEvent& operator=(const AutoResetEvent&); // non-copyable
  bool flag_;
  std::mutex protect_;
  std::condition_variable signal_;
};

AutoResetEvent::AutoResetEvent(bool initial)
: flag_(initial)
{
}

void AutoResetEvent::Set()
{
  std::lock_guard<std::mutex> _(protect_);
  flag_ = true;
  signal_.notify_one();
}

void AutoResetEvent::Reset()
{
  std::lock_guard<std::mutex> _(protect_);
  flag_ = false;
}

bool AutoResetEvent::WaitOne()
{
  std::unique_lock<std::mutex> lk(protect_);
  while( !flag_ ) // prevent spurious wakeups from doing harm
    signal_.wait(lk);
  flag_ = false; // waiting resets the flag
  return true;
}


AutoResetEvent event;

void otherthread()
{
  event.WaitOne();
  printf("Hello from other thread!\n");
}


int main()
{
  std::thread h(otherthread);
  printf("Hello from the first thread\n");
  event.Set();

  h.join();
}

Output:

Hello from the first thread
Hello from other thread!

Update

In the comments below tobsen notes that AutoResetEvent has the semantics of signal_.notify_all() instead of signal_.notify_one(). I haven't changed the code because the accepted answer to the first question used pthread_cond_signal as opposed to pthread_cond_broadcast and I am leading with the statement that this is a faithful translation of that answer.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 1
    In fact, is can produce a deadlock if Set is executed before WaitOne (as explained in the answer to the question linked in this answer) – Johannes S. Apr 14 '13 at 15:08
  • Works fine. No chance of deadlocks thanks to `bool flag_` and [how `wait()` works with `std::unique_lock`](http://en.cppreference.com/w/cpp/thread/condition_variable/wait). – Kay Zed Aug 09 '16 at 07:58
  • you might want to change `signal_.notify_one();` to `signal_.notify_all();` to reflect the behaviour of the `AutoResetEvent` Class OP refers to. – tobsen Aug 24 '17 at 12:52
  • @tobsen: Thanks! I've updated my answer with this information. – Howard Hinnant Aug 24 '17 at 15:49
  • Is it OK that flag_ is not atomic? – dmitry1100 Nov 14 '17 at 10:49
  • 2
    Yes. `flag_` is always read and written under the protection of the mutex, and thus need not be (and should not be) atomic. – Howard Hinnant Nov 14 '17 at 15:18
  • The one thing Howard's execellent response left out was WaitOne(w/Timeout). So I got the idea for this from C++ Concurrency In Action: pg 91 (Chap. 4 Sync Concur oper). bool AutoResetEvent::WaitOne(uint32_t timeToWaitMs) { namespace chr = std::chrono; auto const timeout = chr::steady_clock::now() + chr::milliseconds(timeToWaitMs); std::unique_lock lk(mtx); while (!done) { if (signal.wait_until(lk, timeout) == std::cv_status::timeout) break; } return done; } – GMAN Apr 03 '18 at 12:14
  • `bool AutoResetEvent::WaitOne(uint32_t timeToWaitMs) { namespace chr = std::chrono; auto const timeout = chr::steady_clock::now() + chr::milliseconds(timeToWaitMs); std::unique_lock lk(mtx); while (!_flag) { if (signal.wait_until(lk, timeout) == std::cv_status::timeout) break; } return _flag; }` – GMAN Apr 03 '18 at 12:31