Is there an easy way to implement AutoResetEvent in C++0x?
Asked Answered
W

1

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?

Walt answered 16/12, 2011 at 18:33 Comment(0)
F
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.

Flash answered 16/12, 2011 at 18:45 Comment(8)
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)Maimonides
Works fine. No chance of deadlocks thanks to bool flag_ and how wait() works with std::unique_lock.Tjirebon
you might want to change signal_.notify_one(); to signal_.notify_all(); to reflect the behaviour of the AutoResetEvent Class OP refers to.Incandescence
@tobsen: Thanks! I've updated my answer with this information.Flash
Is it OK that flag_ is not atomic?Nestorius
Yes. flag_ is always read and written under the protection of the mutex, and thus need not be (and should not be) atomic.Flash
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). <code>bool AutoResetEvent::WaitOne(uint32_t timeToWaitMs) { namespace chr = std::chrono; auto const timeout = chr::steady_clock::now() + chr::milliseconds(timeToWaitMs); std::unique_lock<std::mutex> lk(mtx); while (!done) { if (signal.wait_until(lk, timeout) == std::cv_status::timeout) break; } return done; }</code>Spondaic
bool AutoResetEvent::WaitOne(uint32_t timeToWaitMs) { namespace chr = std::chrono; auto const timeout = chr::steady_clock::now() + chr::milliseconds(timeToWaitMs); std::unique_lock<std::mutex> lk(mtx); while (!_flag) { if (signal.wait_until(lk, timeout) == std::cv_status::timeout) break; } return _flag; }Spondaic

© 2022 - 2024 — McMap. All rights reserved.