Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a UNIX/pthreads equivalent to Windows manual reset events?

Briefly, a manual reset event is a synchronization construct which is either in the "signaled" or "nonsignaled" state. In the signaled state, any thread which calls a wait function on the event will not block and execution will continue unaffected. Any and all threads which calls a wait function on a nonsignaled object will block until the event enters the signaled state.

The the transition between the signaled and nonsignaled states occurs only as a result of explicit calls to functions such as SetEvent and ResetEvent.

I've built a synchronization mechanism on Windows which uses both these manual reset events and their auto-reset siblings. The auto-reset mechanism can be easily replicated with a semaphore, but I'm struggling to find an equivalent for the manual-reset variety.

In particular, while a condition variable with "notify all" functionality might appear similar at first glance, it has considerably different (perhaps non-functional) behavior when you consider the fact that it requires an associated mutex. First, before the thread can wait on a condvar, it must get the associated mutex. In addition to the cost of getting and releasing the mutex, this serializes unnecessarily all the threads which are about to wait. On wake, even though all threads are notified, only one thread will actually get the mutex at a time, incurring additional performance and concurrency penalties, since the mutex serves no purpose in this case.

The release case is especially poor on a multi-CPU system given that the simultaneous release of all waiters guarantees that the difference between a condvar and a Windows event will be observable - with an Event, at N threads will become runnable on an N CPU system, and can run in parallel, while with a condvar - even with an implementation that avoids the thundering herd - the threads can only leak out one at a time through the associated mutex.

Any pointers to a construct that better imitates the behavior of manual reset events would be greatly appreciated. The closest I can find is a barrier - this allows the unsynchronized approach and release of multiple threads to the barrier - but the barrier "breaks" based on waiting thread count rather than an explicit application call, which is what I need.

like image 310
BeeOnRope Avatar asked Dec 08 '09 19:12

BeeOnRope


People also ask

What is pthreads in C?

The POSIX thread libraries are a standards based thread API for C/C++. It allows one to spawn a new concurrent process flow. It is most effective on multi-processor or multi-core systems where the process flow can be scheduled to run on another processor thus gaining speed through parallel or distributed processing.

What is posix thread programming?

POSIX Threads, commonly known as pthreads, is an execution model that exists independently from a language, as well as a parallel execution model. It allows a program to control multiple different flows of work that overlap in time.

How to terminate a thread in linux?

pthread_exit() is a function used to terminate the thread where this function is called. This is a proper termination. pthread_exit() cannot be used to affect any other thread.


2 Answers

It's Linux-only (I only mention it because you have a "linux" tag), but I think you could build something like this on the futex syscall. See Ulrich Drepper's paper on Futexes for the gory details.

Very roughly, I envisage something along the lines of

void inline gate_wait(volatile int *gate)
{
    if (*gate)
        while (futex(gate, FUTEX_WAIT, 1, 0, 0, 0) == EINTR)
            ;
}

int inline gate_open(volatile int *gate)
{
    *gate = 0;
    return futex(gate, FUTEX_WAKE, INT_MAX, 0, 0, 0);
}

void inline gate_close(volatile int *gate)
{
    *gate = 1;
}

If you do build this "gate" synchronisation primitive on top of futexes, it might be worth contributing it to Rusty Russell's userspace futex library.

like image 198
caf Avatar answered Oct 06 '22 15:10

caf


if all the set/reset operations are in single thread you can easily use a pipe: the "event" is non-signaled/signaled when the pipe is empty/non-empty. To block on the "event" use select or poll on the read end of the pipe. To set the "event" write a byte to the write end. To reset the "event" just empty the pipe by reading the byte from the read end.

like image 32
lucho Avatar answered Oct 06 '22 13:10

lucho