What is the C++ equivalent for AutoResetEvent under Linux?
Asked Answered
S

7

9

The description of AutoResetEvent in MSDN

I'm trying to port a Thread Pool implemented in C# to C++ under Linux. I don't know which functions I should use that have similar behaviors to "AutoResetEvent".

Sugihara answered 14/11, 2011 at 21:15 Comment(0)
K
12

An AutoResetEvent is most akin to a binary semaphore. 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:

#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.

Krute answered 14/11, 2011 at 22:21 Comment(0)
T
4

Conditional variables are NOT the equivalent of 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. A calls WaitOne() and B calls 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.

Now in C, imagine two threads C and D. C calls wait(), D calls notify(). If C is waiting already when D calls notify() everything is ok. 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".

Be very careful about this.

Tablet answered 15/11, 2011 at 13:26 Comment(0)
W
3

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.

See e.g. this tutorial for details on condition variables in POSIX threads.

Wolcott answered 14/11, 2011 at 21:39 Comment(3)
Microsoft likes to blur the distinction between "libraries", "platforms" and "languages" into one big muddle that forces you to "buy Microsoft". In fact, the "AutoResetEvent" class in .Net is a wrapper around the "Event" primitive in Win32, and analogous to "condition variables" in PThreads. Learn PThreads for Linux. PThreads can be used on other platforms besides Linux, and with other languages (C, Python, etc etc) besides C++.Bumpy
Just wondering, would it be easier to implement it using boost:thread library?Sugihara
@derekhh: I don't know about "easier", condition variables are a fairly simple construct, but if you're already using boost::thread (which IMO is a perfectly good choice), by all means use its condition variable wrapper, it'll fit right in with the rest of your code: boost.org/doc/libs/1_47_0/doc/html/thread/…Wolcott
M
2

You can easily re-implement Win32 API Event objects using POSIX mutexes and condition variables.

However some of the comments above make me state this:

A condition variable is not analogous to an Event object. 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.

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_;
};
Mallee answered 14/11, 2011 at 22:19 Comment(0)
N
1

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
(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.

Nuss answered 5/9, 2013 at 15:33 Comment(0)
T
0

Well, odds are it's most like a mutex -- you have a number of callers going for a shared resource, but only one is allowed in. In the mutex case, callers would try to get the mutex (e.g. phtread_mutex_lock), do their thing, then release (pthread_mutex_unlock) so that some other caller can then get in.

Tatianatatianas answered 14/11, 2011 at 21:34 Comment(1)
No, it's not at all like a mutex. It's more like a condition variable.Outwork
M
0

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:

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(&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.

This example blocks the waiting thread until SIGUSR1 is delivered. The signal only reaches that specific thread because of using pthread_kill.

Manners answered 13/6, 2019 at 13:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.