WaitForSingleObject and WaitForMultipleObjects equivalent in Linux?
Asked Answered
R

4

31

I am migrating an applciation from windows to linux. I am facing problem with respect to WaitForSingleObject and WaitForMultipleObjects interfaces.

In my application I spawn multiple threads where all threads wait for events from parent process or periodically run for every t seconds.

I have checked pthread_cond_timedwait, but we have to specify absolute time for this.

How can I implement this in Unix?

Recalcitrate answered 27/4, 2010 at 7:59 Comment(0)
T
13

Stick to pthread_cond_timedwait and use clock_gettime. For example:

struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 10; // ten seconds
while (!some_condition && ret == 0)
    ret = pthread_cond_timedwait(&cond, &mutex, &ts);

Wrap it in a function if you wish.


UPDATE: complementing the answer based on our comments.

POSIX doesn't have a single API to wait for "all types" of events/objects as Windows does. Each one has its own functions. The simplest way to notify a thread for termination is using atomic variables/operations. For example:

Main thread:

// Declare it globally (argh!) or pass by argument when the thread is created
atomic_t must_terminate = ATOMIC_INIT(0);

// "Signal" termination by changing the initial value
atomic_inc(&must_terminate); 

Secondary thread:

// While it holds the default value
while (atomic_read(&must_terminate) == 0) {
    // Keep it running...
}
// Do proper cleanup, if needed
// Call pthread_exit() providing the exit status

Another alternative is to send a cancellation request using pthread_cancel. The thread being cancelled must have called pthread_cleanup_push to register any necessary cleanup handler. These handlers are invoked in the reverse order they were registered. Never call pthread_exit from a cleanup handler, because it's undefined behaviour. The exit status of a cancelled thread is PTHREAD_CANCELED. If you opt for this alternative, I recommend you to read mainly about cancellation points and types.

And last but not least, calling pthread_join will make the current thread block until the thread passed by argument terminates. As bonus, you'll get the thread's exit status.

Theomania answered 27/4, 2010 at 8:10 Comment(12)
@Theomania But is it mandatory on cond signal for threads which are waiting for the signal to lock the mutex and check the condition variable even if they are not contending for any resource.Recalcitrate
@Sirish POSIX doesn't have a single API to wait for "all types" of events/objects. Each one has its own functions. If you specify the type of event you're interested in, I might be able to indicate the most suitable API.Theomania
@Theomania In my application I want each thread spawned by parent thread to wait for terminate event from parent and do some cleanup on terminate and parent to wait untill all spawned threads are terminatedRecalcitrate
@Sirish What do you mean by terminate event? An atomic variable shared by all threads? Or you want a suggestion from me? For the parent-wait-threads part, you can sequentially call pthread_join for each thread you wish to wait.Theomania
@Sirish I gotta go now, but my suggestion for the terminate event without locking, is an atomic variable, or pthread_cancel+ pthread_cleanup_push. The first sends a cancellation request to the desired thread, and the second registers cleanup callbacks, and must be invoked by the thread itself. The cleanup callbacks will be invoked upon a cancellation request. I recommend you to read more on this subject, mainly cancellation points and types. Hopefully, this will answer your question(s).Theomania
I'll edit my answer later (when I get free time) to include all these informations.Theomania
We used ACE framework, so solved it using ACE thread groups and we can address an entire thread group with an event message and parent thread waits for all threads to exit.Recalcitrate
You can see my answer for another option when it comes to WaitForMultipleObjects.Dependence
Hi, what to include to get atomic operations? I tried #include <atomic.h> and #include <asm/atomic.h> and both doesn't exist.Midriff
@AfrizaNArief until C11 (and C++11, fwiw) came to life, there was no standard way to use atomic operations. However, most compilers already provided their own implementations (GCC's for example). The Linux Kernel provides its own implementation as well (which is the one I used in the answer). To use the kernel impl, install the kernel headers & add its include dir to the "include path" for compilation - then it will find the required header, <asm/atomic.h>.Theomania
Updated link: Linux Kernel provides its own implementation. The previous one is now broken.Theomania
Using a busy loop like this answer suggets is an extremely bad idea and will cause extreme CPU and scheduler issues. Furthermore, using plain atomic instructions does not guarantee proper memory ordering on CPUs like ARM. pthreads is not an API I am familiar with, but please god use an actual proper semaphore API from pthreads instead of this terrible answer.Hollands
D
13

For what it's worth, we (NeoSmart Technologies) have just released an open source (MIT licensed) library called pevents which implements WIN32 manual and auto-reset events on POSIX, and includes both WaitForSingleObject and WaitForMultipleObjects clones.

Although I'd personally advise you to use POSIX multithreading and signaling paradigms when coding on POSIX machines, pevents gives you another choice if you need it.

Dependence answered 16/10, 2011 at 5:47 Comment(0)
S
2

I realise this is an old question now, but for anyone else who stumbles across it, this source suggests that pthread_join() does effectively the same thing as WaitForSingleObject():

http://www.ibm.com/developerworks/linux/library/l-ipc2lin1/index.html

Good luck!

Spumescent answered 11/4, 2012 at 5:16 Comment(3)
WaitForSingleObject, WaitForMultipleObjects and friends also take a timout. I don't believe pthread_join provides it.Waterage
pthread_timedjoin_np if it is available on your system, provides a timeout parameterDrupe
your link doesn't seem to point to the right place. I'm planning to use your answer. still good in 2019?Lordosis
D
1

For WaitForMultipleObjects with false WaitAll try this:

#include <unistd.h>
#include <pthread.h>
#include <stdio.h>

using namespace std;

pthread_cond_t condition;
pthread_mutex_t signalMutex;
pthread_mutex_t eventMutex;
int finishedTask = -1;

void* task(void *data)
{
    int num = *(int*)data;
    // Do some
    sleep(9-num);
    // Task finished
    pthread_mutex_lock(&eventMutex); // lock until the event will be processed by main thread
    pthread_mutex_lock(&signalMutex); // lock condition mutex
    finishedTask = num; // memorize task number
    pthread_cond_signal(&condition);
    pthread_mutex_unlock(&signalMutex); // unlock condtion mutex
}

int main(int argc, char *argv[])
{
    pthread_t thread[10];

    pthread_cond_init(&condition, NULL);
    pthread_mutex_init(&signalMutex, NULL); // First mutex locks signal
    pthread_mutex_init(&eventMutex, NULL); // Second mutex locks event processing

    int numbers[10];

    for (int i = 0; i < 10; i++) {
        numbers[i] = i;
        printf("created %d\n", i); // Creating 10 asynchronous tasks
        pthread_create(&thread[i], NULL, task, &numbers[i]);
    }

    for (int i = 0; i < 10;)
    {
        if (finishedTask >= 0) {
            printf("Task %d finished\n", finishedTask); // handle event
            finishedTask = -1; // reset event variable
            i++;
            pthread_mutex_unlock(&eventMutex); // unlock event mutex after handling
        } else {
            pthread_cond_wait(&condition, &signalMutex); // waiting for event
        }
    }

    return 0;
}
Djokjakarta answered 19/10, 2015 at 8:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.