Windows Event implementation in Linux using conditional variables?
Asked Answered
T

3

11

I am trying to implement very simple Windows events in Linux. Only for my scenario - 3 threads, 1 main and 2 secondary. Each of secondary threads raise 1 event by SetEvent and main thread wait it. Example:

int main()
{
    void* Events[2];
    Events[0] = CreateEvent();
    Events[1] = CreateEvent();

    pthread_start(Thread, Events[0]);
    pthread_start(Thread, Events[1]);

    WaitForMultipleObjects(2, Events, 30000) // 30 seconds timeout

    return 0;
}

int* thread(void* Event)
{
    // Do something
    SetEvent(Event);
    // Do something
}

So, to implement it, i use conditional variables. But my question is - is this a right way? Or i doing something wrong? My implementation:

// Actually, this function return pointer to struct with mutex and cond
// here i just simplified example
void* CreateEvent(mutex, condition)
{
    pthread_mutex_init(mutex, NULL);
    pthread_cond_init(condition, NULL);
}

bool SetEvent (mutex, condition)
{
    pthread_mutex_lock(mutex);
    pthread_cond_signal(condition);
    pthread_mutex_unlock(mutex);
}

int WaitForSingleObject(mutex, condition, timeout)
{
    pthread_mutex_lock(mutex);
    pthread_cond_timedwait(condition, mutex, timeout);
    pthread_mutex_unlock(mutex);
}

// Call WaitForSingleObject for each event. 
// Yes, i know, that its a wrong way, but it should work in my example.
int WaitForMultipleObjects(count, mutex[], condition[], timeout);

And all seems good, but i think, that problem will appear when i call WaitFor.. function in Main thread before SetEvent in secondary thread will be called. In Windows, it worked well, but in Linux - only idea is described above.

Maybe you tell me the better way to solve it? Thank you.

UPD: Timeout is very important, because one of the secondary threads may not pass SetEvent().

Teresitateressa answered 23/10, 2012 at 12:27 Comment(2)
We have an open source (MIT-licensed) library called pevents which implements WIN32 manual and auto-reset events on linux, and includes both WaitForSingleObject and WaitForMultipleObjects clones: github.com/NeoSmart/PEventsMasterly
possible duplicate of pthread-like windows manual-reset eventThresathresh
L
2

There was similar question on stackoverflow already: WaitForSingleObject and WaitForMultipleObjects equivalent in linux

In addition you can use semaphores:

sem_t semOne  ;
sem_t semTwo  ;
sem_t semMain ;

In main thread:

sem_init(semOne,0,0) ;
sem_init(semTwo,0,0) ;
sem_init(semMain,0,0) ;

...


sem_wait(&semMain);

// Thread 1
sem_wait(&semOne);
sem_post(&semMain);


// Thread 2
sem_wait(&semTwo);
sem_post(&semMain);

Detailed description and various examples could be found here: ------http://www.ibm.com/developerworks/linux/library/l-ipc2lin3/index.html

The previous link is no longer available. The most recent archived version at The Internet Archive's Wayback Machine is: https://web.archive.org/web/20130515223326/http://www.ibm.com/developerworks/linux/library/l-ipc2lin3/index.html

Lurlinelusa answered 23/10, 2012 at 13:3 Comment(4)
Thank you, but what about timeout? As i know, semaphores doesn't have it.Teresitateressa
You could simply use sem_timedwait() instead of sem_wait().Lurlinelusa
I think, that semaphores can't timedwait... Thank you )Teresitateressa
Why they can't wait? There are some bugs regarding sem_timewait(). You can find some clues here or here.Lurlinelusa
T
4

Basing this on the description of WaitForSingleObject

The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters the wait state until the object is signaled or the time-out interval elapses.

The difference between that behavior and the code is that the code will always wait on the condition variable, as it does not check a predicate. This introduces synchronization issues between the pthread_condt_timewait and pthread_cond_signal calls.

The general idiom for signalling a condition variable is:

lock mutex
set predicate
unlock mutex
signal condition variable

And when waiting for a condition variable:

lock mutex
while ( !predicate )
{ 
  wait on condition variable
}
unlock mutex

Based on what is trying to be accomplished, a separate bool could be used as a predicate for each Event. By introducing a predicate, WaitForSingleObject should only wait on the condition variable if the Event has not been signaled. The code would look similar to the following:

bool SetEvent (mutex, condition)
{
    pthread_mutex_lock(mutex);                 // lock mutex
    bool& signalled = find_signal(condition);  // find predicate
    signalled = true;                          // set predicate
    pthread_mutex_unlock(mutex);               // unlock mutex
    pthread_cond_signal(condition);            // signal condition variable
}

int WaitForSingleObject(mutex, condition, timeout)
{
    pthread_mutex_lock(mutex);                         // lock mutex
    bool& signalled = find_signal(condition);          // find predicate
    while (!signalled)
    {
      pthread_cond_timedwait(condition, mutex, timeout);
    }
    signalled = false;                                 // reset predicate
    pthread_mutex_unlock(mutex);                       // unlock mutex
}
Tancred answered 23/10, 2012 at 13:27 Comment(0)
L
2

There was similar question on stackoverflow already: WaitForSingleObject and WaitForMultipleObjects equivalent in linux

In addition you can use semaphores:

sem_t semOne  ;
sem_t semTwo  ;
sem_t semMain ;

In main thread:

sem_init(semOne,0,0) ;
sem_init(semTwo,0,0) ;
sem_init(semMain,0,0) ;

...


sem_wait(&semMain);

// Thread 1
sem_wait(&semOne);
sem_post(&semMain);


// Thread 2
sem_wait(&semTwo);
sem_post(&semMain);

Detailed description and various examples could be found here: ------http://www.ibm.com/developerworks/linux/library/l-ipc2lin3/index.html

The previous link is no longer available. The most recent archived version at The Internet Archive's Wayback Machine is: https://web.archive.org/web/20130515223326/http://www.ibm.com/developerworks/linux/library/l-ipc2lin3/index.html

Lurlinelusa answered 23/10, 2012 at 13:3 Comment(4)
Thank you, but what about timeout? As i know, semaphores doesn't have it.Teresitateressa
You could simply use sem_timedwait() instead of sem_wait().Lurlinelusa
I think, that semaphores can't timedwait... Thank you )Teresitateressa
Why they can't wait? There are some bugs regarding sem_timewait(). You can find some clues here or here.Lurlinelusa
L
0

I think semaphore is a better solution here, because it can be used inter-process. You can wrap the interface, if name is not provide, then use pthread_ to initialize it for intra-process to use, which can short the resource usage, but when name used, try to use sem initialize it, for intra-process use.

Lunge answered 29/10, 2015 at 4:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.