web-dev-qa-db-fra.com

WaitForSingleObject et WaitForMultipleObjects équivalents sous Linux?

Je migre une applciation de Windows vers Linux. Je rencontre un problème concernant les interfaces WaitForSingleObject et WaitForMultipleObjects.

Dans mon application, je génère plusieurs threads où tous les threads attendent des événements du processus parent ou s'exécutent périodiquement toutes les t secondes.

J'ai vérifié pthread_cond_timedwait, mais nous devons spécifier le temps absolu pour cela.

Comment puis-je implémenter cela dans Unix?

28
Poorna

S'en tenir à pthread_cond_timedwait et utilise clock_gettime. Par exemple:

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);

Enveloppez-le dans une fonction si vous le souhaitez.


MISE À JOUR: complétant la réponse sur la base de nos commentaires.

POSIX n'a ​​pas une seule API pour attendre "tous les types" d'événements/objets comme le fait Windows. Chacun a ses propres fonctions. La façon la plus simple de notifier un thread pour la terminaison est d'utiliser des variables/opérations atomiques. Par exemple:

Fil principal:

// 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); 

Fil secondaire:

// 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

Une autre alternative consiste à envoyer une demande d'annulation à l'aide de pthread_cancel. Le thread en cours d'annulation doit avoir appelé pthread_cleanup_Push pour enregistrer tout gestionnaire de nettoyage nécessaire. Ces gestionnaires sont appelés dans l'ordre inverse de leur enregistrement. N'appelez jamais pthread_exit à partir d'un gestionnaire de nettoyage, car il s'agit d'un comportement non défini. Le statut de sortie d'un thread annulé est PTHREAD_CANCELED. Si vous optez pour cette alternative, je vous recommande de lire principalement sur les points et types d'annulation.

Et enfin et surtout, appeler pthread_join fera le bloc de thread actuel jusqu'à ce que le thread passé par l'argument se termine. En bonus, vous obtiendrez le statut de sortie du thread.

12
jweyrich

Pour ce que ça vaut, nous (NeoSmart Technologies) venons de publier une bibliothèque open source (sous licence MIT) appelée pevents qui implémente les événements manuels et de réinitialisation automatique WIN32 sur POSIX, et inclut les clones WaitForSingleObject et WaitForMultipleObjects.

Bien que je vous conseille personnellement d'utiliser les paradigmes de multithreading et de signalisation POSIX lors du codage sur les machines POSIX, pevents vous donne un autre choix si vous en avez besoin.

12
Mahmoud Al-Qudsi

Je me rends compte que c'est une vieille question maintenant, mais pour toute personne qui tombe dessus, cette source suggère que pthread_join () fait effectivement la même chose que WaitForSingleObject ():

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

Bonne chance!

1
eskimo9

Pour WaitForMultipleObjects avec false WaitAll essayez ceci:

#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;
}
1
Sorcerer