Thread: Is there an equivalent to WaitForMultipleObjects() in Linux?

  1. #1
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658

    Is there an equivalent to WaitForMultipleObjects() in Linux?

    In the case of Windows the native function WaitForMultipleObjects() is useful for waiting for a combined mutex and semaphore. In the specific case of waiting for a mutex and semaphore, the call has to get a lock on both, and decrements the non-zero semaphore count, all in a single atomic call before returning back to the caller. One issue is that all of the "handles" used for WaitForMultipleObjects() have to be in array. In my case, I used defines to give names to specific handles within the array to make the code easier to read.

    Also spurious wake up is not an issue for either WaitForSingleObject() or WaitForMultipleObjects().

    WaitForSingleObject function (Windows)

    WaitForMultipleObjects function (Windows)

    Almost every other operating system I've worked with, include something similar to WaitForMultipleObjects() when used to wait for any of a group of objects, such as wait for any of event, message, or timeout, and some of these other operating systems include the ability similar to wait for two objects, such as mutex and semaphore.

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    You have to roll your own. Here is an old design that uses a subscription model so there is no polling: http://taz.newffr.com/TAZ/Win32/codi...aitfor_api.pdf

    Here's an implementation just for Events: GitHub - neosmart/pevents: Implementation of Win32 events for *nix platforms, built on top of pthreads.

    gg

  3. #3
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    I'll have to examine the workaround more carefully, but it appears that the wait for all variation is meant to handle multiple events, not a combination of mutex and event (in my example case, the event is a semaphore), where the mutex is normally unlocked, which I'm thinking could result in a polling loop on the mutex while waiting for the semaphore count to go non-zero. There's also the issue of decrementing the semaphore count as part of the "atomic" like wait before returning to the caller.

    It seems the best workaround for the specific example I mentioned is to use a posix message queue, since there is native support for that in the kernel. If that's not enough, and an application needs a special set of features, I assume that a device driver could be implemented, using spinlock as needed to replace the functionality of a mutex.
    Last edited by rcgldr; 11-13-2017 at 12:54 AM.

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    I have a Thread object that I made compatible with pevents WFMO. In Win32, a thread HANDLE is "signaled" when the thread exits. Internal to the Thread object is a m_evThreadExited pevent (manual reset = true) that is signaled when the Thread function exits (via an internal thread function wrapper that signals the event when the user's thread function returns).

    Assuming you have a similar wrapper for sem_t, it could also have an internal m_evSemAcquired (manual reset = false) that is used in WFMO calls. The problem becomes who is going to signal this event? The first thing that comes to mind is a dedicated thread that calls sem_trywait() and signals m_evSemAcquired once it succeeds. Something like this (off the top of my head):
    Code:
    Semaphore sem;
    ...
    Thread A
    sem.StartAsyncWait();
    int status = WFMO(...);
    sem.StopAsyncWait();
    ...
    Thread B
    sem.StartAsyncWait();
    int status = WFMO(...);
    sem.StopAsyncWait();
    Across thread A and B, there would only be one async-wait-thread that services the sem instance. The Start/Stop calls would need to be reference counted so that only the last Stop really stops the async-wait-thread - and only the first Start actually starts the thread. Because m_evSemAcquired is an auto-reset event, only one of the WFMO() calls will be the winner once the sem is acquired.

    So this won't really work as-is. Both WFMO calls could return some other index even though sem was acquired by the thread. This could be fixed by letting Stop know if the sem was the winner:
    Code:
    sem.StartAsyncWait();
    int status = WFMO(...);
    sem.StopAsyncWait(status == semIndex);
    ...
    void Semaphore::StopAsyncWait(bool bWinner)
    {
        [mutex this method with Start method]
        if (bWinner)
            m_bHaveWinner = true;
        
        --m_refCount;
        if (m_refCount == 0)
        {
            this->DoStopAsncWait();
            
            int sem_val;
            sem_getvalue(&m_s, &sem_val);
            const bool bSemAcquired = (sem_val <= 0);
            bool bDoPost = !m_bHaveWinner && bSemAcquired;
            
            if (m_evSemAcquired.IsSignaled())
            {
                // async-wait-thread acquired us outside of last WFMO call
                m_evSemAcquired.Reset();
                bDoPost = true;
            }
            
            if (bDoPost)
                sem_post(&m_s); // undo "accidental" acquire
                
            m_bHaveWinner = false; // or reset on first Start call
        }
    }
    This allows any acquisition of sem that didn't result in a WFMO() winner to be "undone". Note that "sem_val <= 0" assumes that Semaphore is really a mutex (sem value is 0 or 1). For a generic semaphore, you would need the track the sem value before and after the async-wait-thread runs. If the sem value decreased, then you know the thread acquired it.

    I think this works

    gg

  5. #5
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    I took a quick look at that. Again the specific case I'm wondering about is WFMO when one of the objects is a mutex, which is normally unlocked (effectively, it's usually signaled). Seems like the mutex part of WFMO would need to handled in some special way. Looks like using a custom device driver is helpful here (since that would allow spinlock to be used as a mutex). Based on a quick look, it appears that Microsoft Azure (high end auto load balancing server language) installs a device driver when it's installed on a Linux based server.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. graphics.h equivalent in Linux??
    By linuxlover in forum C Programming
    Replies: 1
    Last Post: 11-28-2010, 02:47 PM
  2. Linux equivalent of con
    By dwks in forum Linux Programming
    Replies: 3
    Last Post: 11-12-2005, 11:58 AM
  3. Linux equivalent to CreateDirectory
    By Rak'kar in forum Linux Programming
    Replies: 2
    Last Post: 07-10-2004, 12:04 PM
  4. .bat equivalent for linux
    By ichijoji in forum Linux Programming
    Replies: 8
    Last Post: 03-07-2004, 08:06 AM
  5. MS Projects equivalent Linux
    By compiler in forum Tech Board
    Replies: 4
    Last Post: 07-08-2003, 10:48 AM

Tags for this Thread