Есть ли простой способ реализовать AutoResetEvent в С++ 0x?

Насколько я понимаю, я задавал этот вопрос раньше: Что такое C++ эквивалент для AutoResetEvent под Linux?

Однако я узнаю, что в С++ 0x библиотека потоков значительно упрощается, поэтому я хочу снова задать этот вопрос, есть ли простой способ реализовать AutoResetEvent в С++ 0x?


person derekhh    schedule 16.12.2011    source источник


Ответы (1)


Вот перевод принятого ответа на ваш первый вопрос для использования инструментов С++ 11:

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

Выход:

Hello from the first thread
Hello from other thread!

Обновить

В комментариях ниже tobsen отмечает, что AutoResetEvent имеет семантику signal_.notify_all() вместо signal_.notify_one(). Я не изменил код, потому что принятый ответ на первый вопрос использовал pthread_cond_signal, а не pthread_cond_broadcast, и я веду с утверждение, что это верный перевод этого ответа.

person Howard Hinnant    schedule 16.12.2011
comment
Фактически, это может привести к взаимоблокировке, если Set выполняется до WaitOne (как объяснено в ответе на вопрос, связанный с этим ответом) - person Johannes S.; 14.04.2013
comment
Работает отлично. Отсутствие взаимоблокировок благодаря bool flag_ и тому, как wait() работает с std::unique_lock. - person Kay Zed; 09.08.2016
comment
вы можете изменить signal_.notify_one(); на signal_.notify_all();, чтобы отразить поведение класса AutoResetEvent, на который ссылается OP. - person tobsen; 24.08.2017
comment
@tobsen: Спасибо! Я обновил свой ответ этой информацией. - person Howard Hinnant; 24.08.2017
comment
Это нормально, что flag_ не является атомарным? - person C0DEF52; 14.11.2017
comment
Да. flag_ всегда читается и записывается под защитой мьютекса и, следовательно, не обязательно должен быть (и не должен быть) атомарным. - person Howard Hinnant; 14.11.2017
comment
Единственная вещь, которую не учел в превосходном ответе Ховарда, это WaitOne(w/Timeout). Так что я получил идею для этого из 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:: миллисекунды (timeToWaitMs); std::unique_lock‹std::mutex› lk(mtx); while (!done) { if (signal.wait_until(lk, timeout) == std::cv_status::timeout) break; } возврат выполнен; } - person GMAN; 03.04.2018