5

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()
        {

        }
    };
Community
  • 1
  • 1
Virus721
  • 8,061
  • 12
  • 67
  • 123
  • The code you have in the constructor looks like it should be in `Signal()`. – caf Oct 13 '15 at 09:11
  • 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. – Virus721 Oct 13 '15 at 09:21
  • 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. – n. m. could be an AI Oct 13 '15 at 09:27
  • 1
    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 http://man7.org/linux/man-pages/man3/sem_post.3.html and http://man7.org/linux/man-pages/man3/sem_wait.3.html There's some good example code on the `sem_wait()` man page. – Andrew Henle Oct 13 '15 at 09:40
  • @AndrewHenle Thanks for your help. I will have a look. I also found a detailed to document about POSIX threads here (in french) : http://www.univ-orleans.fr/lifo/Members/Sylvain.Jubertie/enseignement/systeme/Processus-Threads.pdf If it doesn't give me what I need i'll have a look to the semaphore things. – Virus721 Oct 13 '15 at 09:43
  • 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. – caf Oct 13 '15 at 10:11
  • I've seen this SO question : http://stackoverflow.com/questions/13675132/pthread-cond-wait-for-2-threads 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. – Virus721 Oct 13 '15 at 11:29
  • Contrary to what other people say, POSIX does not have a concept of signals at all. – SergeyA Oct 13 '15 at 13:40
  • @SergeyA: Can you substantiate that claim? Even C has signals (C11 draft standard, `7.14 Signal handling `. 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. – EOF Oct 13 '15 at 15:50
  • @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. – SergeyA Oct 13 '15 at 16:39
  • @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"). – caf Oct 14 '15 at 02:27

5 Answers5

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.

tonso
  • 1,760
  • 1
  • 11
  • 19
  • Thanks for your answer. Will have a look at this. – Virus721 Oct 13 '15 at 10:00
  • 1
    No, posix condition variables are not a drop-in replacement for signals. Which is a pity. – SergeyA Oct 13 '15 at 13:39
  • @SergeyA I didn't mean that those are equal. But the condition variables fit the situation. – tonso Oct 13 '15 at 14:17
  • 1
    pthread (and C++11) condition_variables are painfully different from Windows signals, especially the manual reset events, which don't need mutexes to work. – lornova Mar 29 '17 at 07:11
14

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

j123b567
  • 3,110
  • 1
  • 23
  • 32
  • 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. – Virus721 Oct 13 '15 at 09:29
  • 1
    Yes, this is Linux specific and I don't know, if it is supported by Android, but there is chance it can be. – j123b567 Oct 13 '15 at 09:31
  • Here is interresting reading about performance of `eventfd` and `pthread_cond` system https://issues.apache.org/jira/browse/TS-2137 It seems that eventfd is 5-times faster. – j123b567 Oct 13 '15 at 12:44
  • This is correct answer, the only problem is, it is not Posix. But Posix simply does not have signals. – SergeyA Oct 13 '15 at 13:40
  • @j123b567, no suprises here. – SergeyA Oct 13 '15 at 13:41
  • This should be the correct answer, at least for those using Linux. Thank you! – Nautilus Aug 14 '17 at 17:26
7

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);
    }
};
caf
  • 233,326
  • 40
  • 323
  • 462
2

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

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
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.