Linux/POSIX equivalent for Win32's CreateEvent, SetEvent, WaitForSingleObject
Asked Answered
F

5

8

I have written a small class for synchronizing threads of both Linux (actually Android) and Windows.

Here is the Win32 implementation of my interface :

    class SyncObjectWin32 : public SyncObject
    {
    private:

        const HANDLE m_hEvent;

    public:

        SyncObjectWin32()
          : m_hEvent( ::CreateEvent( NULL, FALSE, FALSE ) )
        {
            if( NULL == m_hEvent )
                throw core::Exception( "sys::SyncObjectWin32::SyncObjectWin32() - Failed to create event." );
        }

        ~SyncObjectWin32()
        {
            ::CloseHandle( m_hEvent );
        }

        void WaitForSignal()
        {
            ::WaitForSingleObject( m_hEvent );
        }

        void Signal()
        {
            ::SetEvent( m_hEvent );
        }
    };

The problem is that i'm not sure what would be the POSIX equivalent. So far i've written the following class, based on this SO question, but since the answer is incomplete i'm not sure about how to finish my class :

    class SyncObjectPosix
    {
    private:

        pthread_mutex_t m_oMutex;

    public:

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

        ~SyncObjectPosix()
        {

        }

        void WaitForSignal()
        {
            pthread_mutex_lock(mutex);                         // lock mutex
            bool & signalled = find_signal( condition );          // find predicate
            while (!signalled)
            {
              pthread_cond_timedwait(condition, m_oMutex, timeout);
            }
            signalled = false;                                 // reset predicate
            pthread_mutex_unlock( m_oMutex );                       // unlock mutex
        }

        void Signal()
        {

        }
    };
Furlough answered 13/10, 2015 at 9:3 Comment(11)
The code you have in the constructor looks like it should be in Signal().Lamdin
Ok thank you. Do you know what would be the type of the "condition" ? Also how could i do an unlimited wait ? And how fast is this ? Because if pthread_cond_timedwait waits, let's say, 1 second, then in some cases there will be a 1 second delay.Furlough
There is no equivalent. A similar facility is POSIX condition variables. You need to read all the man pages in the pthread_cond_* series, and then read a tutorial or two on how to actually use them.Spaniel
The semantics of Windows and POSIX synchronization methods differ, so the cross-platform equivalent depends on how you're using one or the other. From the way you're using SetEvent() and WaitForSingleObject(), a semaphore would also work. See man7.org/linux/man-pages/man3/sem_post.3.html and man7.org/linux/man-pages/man3/sem_wait.3.html There's some good example code on the sem_wait() man page.Egalitarian
@AndrewHenle Thanks for your help. I will have a look. I also found a detailed to document about POSIX threads here (in french) : univ-orleans.fr/lifo/Members/Sylvain.Jubertie/enseignement/… If it doesn't give me what I need i'll have a look to the semaphore things.Furlough
It's pthread_cond_t. If you don't want to wait with timeout, there's pthread_cond_wait(). There's no significant delay in waking a thread waiting on a condition variable, as long as it is able to re-acquire the mutex. I'm not sure what the implementation of find_signal() is supposed to be - you could/should just make bool signalled another class private variable.Lamdin
I've seen this SO question : #13675632 But what i don't understand is why one would need to test a "shared state" instead of simply waiting for the condition to be singaled. Isn't it ok to just call pthread_cond_wait() on a thread and pthread_cond_signal on another thread ? Thanks.Furlough
Contrary to what other people say, POSIX does not have a concept of signals at all.Preconcerted
@SergeyA: Can you substantiate that claim? Even C has signals (C11 draft standard, 7.14 Signal handling <signal.h>. POSIX adds further signal-handling (like better specified sigaction() to replace signal(), and kill()ing other processes rather than only raise()ing a signal for the process itself.Loring
@EOF, this is likely a mixture of naming. Posix has signals (the ones you are taling about), but those have nothing to do with signals as represented as windows events. Probably I should've refrained from using word 'singal' in mixed context.Preconcerted
@VIrus721: You need to pair it with shared state for two reasons: pthread_cond_wait() is allowed to wake up without having been signalled ("spurious wakeup"), and because otherwise if you signalled it before waiting, it would potentially wait forever (a pthread_cond_signal() with no waiting thread is "lost").Lamdin
L
17

The POSIX equivalent for what you described is POSIX condition variables. Note that condition variable must always be used in pair with a POSIX mutex, but quite frequently several condition variables use the same mutex, so if you aren't going to use the mutex exclusively for the condition variable, you shouldn't place it in the class. The mappings by meaning in your case between Win32 and POSIX API should be:

CreateEvent -> pthread_cond_init

CloseHandle -> pthread_cond_destroy

WaitForSingleObject -> pthread_cond_wait or pthread_cond_timedwait

SetEvent -> pthread_cond_signal or pthread_cond_broadcast

Fortunately, there is a lot of documentation regarding this, though I recommend the fundamental Programming POSIX Threads.

Lashawna answered 13/10, 2015 at 9:44 Comment(4)
Thanks for your answer. Will have a look at this.Furlough
No, posix condition variables are not a drop-in replacement for signals. Which is a pity.Preconcerted
@Preconcerted I didn't mean that those are equal. But the condition variables fit the situation.Lashawna
pthread (and C++11) condition_variables are painfully different from Windows signals, especially the manual reset events, which don't need mutexes to work.Sunlight
S
17

Check also eventfd. It seems to be almost equivalent of CreateEvent if you need just one consumer and one producer.

CreateEvent --> eventfd

CloseHandle --> close

SetEvent --> write

WaitForSingleObject --> read

WaitForMultipleObjects --> select and read corresponding fd

Some more reading http://www.sourcexr.com/articles/2013/10/26/lightweight-inter-process-signaling-with-eventfd

Shayneshays answered 13/10, 2015 at 9:26 Comment(6)
Thanks for your help. I assume this is linux stuff and not POSIX right ? I'm ok with linux API too as long as they are supported in the Android NDK.Furlough
Yes, this is Linux specific and I don't know, if it is supported by Android, but there is chance it can be.Shayneshays
Here is interresting reading about performance of eventfd and pthread_cond system issues.apache.org/jira/browse/TS-2137 It seems that eventfd is 5-times faster.Shayneshays
This is correct answer, the only problem is, it is not Posix. But Posix simply does not have signals.Preconcerted
@j123b567, no suprises here.Preconcerted
This should be the correct answer, at least for those using Linux. Thank you!Oratorical
L
17

The POSIX equivalent for what you described is POSIX condition variables. Note that condition variable must always be used in pair with a POSIX mutex, but quite frequently several condition variables use the same mutex, so if you aren't going to use the mutex exclusively for the condition variable, you shouldn't place it in the class. The mappings by meaning in your case between Win32 and POSIX API should be:

CreateEvent -> pthread_cond_init

CloseHandle -> pthread_cond_destroy

WaitForSingleObject -> pthread_cond_wait or pthread_cond_timedwait

SetEvent -> pthread_cond_signal or pthread_cond_broadcast

Fortunately, there is a lot of documentation regarding this, though I recommend the fundamental Programming POSIX Threads.

Lashawna answered 13/10, 2015 at 9:44 Comment(4)
Thanks for your answer. Will have a look at this.Furlough
No, posix condition variables are not a drop-in replacement for signals. Which is a pity.Preconcerted
@Preconcerted I didn't mean that those are equal. But the condition variables fit the situation.Lashawna
pthread (and C++11) condition_variables are painfully different from Windows signals, especially the manual reset events, which don't need mutexes to work.Sunlight
L
8

The pthreads equivalent of your code is:

class SyncObjectPosix
{
private:

    bool signalled;
    pthread_mutex_t mutex;
    pthread_cond_t cond;

public:

    SyncObjectPosix()
    {
        signalled = false;
        pthread_mutex_init(&mutex, NULL);
        pthread_cond_init(&cond, NULL);
    }

    ~SyncObjectPosix()
    {
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond);
    }

    void WaitForSignal()
    {
        pthread_mutex_lock(&mutex);
        while (!signalled)
        {
            pthread_cond_wait(&cond, &mutex);
        }
        signalled = false;
        pthread_mutex_unlock(&mutex);
    }

    void Signal()
    {
        pthread_mutex_lock(&mutex);
        signalled = true;
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
    }
};
Lamdin answered 14/10, 2015 at 4:23 Comment(0)
E
4

Our open-source pevents library is an implementation of just that for all platforms. It's a very small (single-file) bit of C++ code that you can just add to your existing project and get access to the Windows event api built on top of pthreads synchronization primitives.

The most important tidbit is that it includes WaitForMultipleObjects support.

https://github.com/neosmart/pevents

Enfield answered 18/8, 2018 at 2:31 Comment(1)
This is a very simple solution and works great!Matilda
M
2

as Win32's CreateEvent use file-path like key to indent the event, I don't think all this answer is good.

check the UNIX:System V IPC

int project_id = 1;
std::string path = "[path]";

//CreateEvent
key_t ipc_key = ftok(path.c_str(),project_id);
int event_id = msgget(ipc_key , IPC_CREAT);

//OpenEvent
key_t ipc_key = ftok(path.c_str(),project_id);
int event_id = msgget(ipc_key , 0);

//SetEvent
std::string send_message = "trump 2024|America first|life equally matter|build the #$% wall"; //

msgsnd(event_id, send_message.c_str(), send_message.size(), IPC_NOWAIT); //NO Block
msgsnd(event_id, send_message.c_str(), send_message.size(), 0); //Block

//WaitForSingleObject
std::string receive_message;
receive_message.resize(128);

msgrcv(event_id , &receive_message[0], receive_message.size(), 0,0);

//CloseHandle
msgctl(event_id , IPC_RMID,NULL);

Be ware even there might be some function got more speed per call, but function base on file description does not go with inter-process as CreateEvent Did.

Using IPC event message queue might solve most of the request,but it does not provide timeout ability, which might cause some problem when some time you don't want to complete freeze your process/thread.

Molliemollify answered 27/10, 2021 at 8:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.