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?

jww
  • 97,681
  • 90
  • 411
  • 885
Sirish
  • 9,183
  • 22
  • 72
  • 107

4 Answers4

14

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.

jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • @jweyrich 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. – Sirish Apr 27 '10 at 08:48
  • @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. – jweyrich Apr 27 '10 at 09:21
  • @jweyrich 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 terminated – Sirish Apr 27 '10 at 09:31
  • @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. – jweyrich Apr 27 '10 at 09:40
  • 1
    @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). – jweyrich Apr 27 '10 at 10:29
  • I'll edit my answer later (when I get free time) to include all these informations. – jweyrich Apr 27 '10 at 11:05
  • 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. – Sirish Sep 18 '11 at 08:09
  • You can see my answer for another option when it comes to WaitForMultipleObjects. – Mahmoud Al-Qudsi Oct 16 '11 at 05:48
  • Hi, what to include to get atomic operations? I tried `#include ` and `#include ` and both doesn't exist. – Afriza N. Arief Feb 21 '12 at 04:27
  • 1
    @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](https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html)). The [Linux Kernel provides its own implementation](https://www.kernel.org/doc/Documentation/atomic_ops.txt) 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, ``. – jweyrich Jun 16 '15 at 18:58
  • Updated link: [Linux Kernel provides its own implementation](https://www.kernel.org/doc/html/v4.17/core-api/atomic_ops.html). The previous one is now broken. – jweyrich Jan 31 '19 at 17:38
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.

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

eskimo9
  • 753
  • 10
  • 24
  • 1
    `WaitForSingleObject`, `WaitForMultipleObjects` and friends also take a timout. I don't believe `pthread_join` provides it. – jww Feb 11 '14 at 13:53
  • 1
    `pthread_timedjoin_np` if it is available on your system, provides a timeout parameter – andrew Mar 16 '17 at 20:40
  • your link doesn't seem to point to the right place. I'm planning to use your answer. still good in 2019? – aneesh joshi Jun 07 '19 at 19:32
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;
}
Sorcerer
  • 190
  • 7