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".
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".
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.
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.
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.
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_;
};
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.
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.
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.
© 2022 - 2024 — McMap. All rights reserved.