C – Les condvars de garantie sont prêts pour la signalisation

J’ai une application simple qui s’interface avec différents matériels. Pour chaque élément matériel, je génère un pthread_t rapport à une fonction de moniteur unique, pour un total de 6 threads: un thread de gestionnaire et cinq threads de travail.

Chaque thread a une routine d’initialisation commune dans laquelle il attend que le thread du gestionnaire le réveille via:

 pthread_mutex_lock(&mMutex); pthread_cond_wait(&mMutex, &condVar); pthread_mutex_lock(&mMutex); 

Le thread principal réveille tous les threads en les signalant un par un:

 pthread_cond_wait(&mMutex1, &condVar1); pthread_cond_wait(&mMutex2, &condVar2); ... pthread_cond_wait(&mMutex5, &condVar5); 

Le code fonctionne vraiment bien, mais c’est parce que j’ai de la chance avec le timing. Il y a une chance lointaine, mais existante, que lorsque le thread principal / gestionnaire émet pthread_cond_signal , l’initialisation du thread ne soit pas encore terminée. Je dois trouver un moyen de garantir que chaque variable de condition a reçu un appel d’ wait par son thread de travail respectif.

Je pourrais toujours créer un statut booléen défini dans le mutex correspondant, mais je ne peux pas effectuer de manière atomique les opérations set et wait en une seule instruction, pour autant que je sache. Je pourrais aussi utiliser un pthread_barrier_t , mais cela garantit simplement que tous les threads ont une ou deux instructions avant de passer leurs appels d’ wait respectifs.

Existe-t-il une méthode éprouvée pour être certain que l’appel d’ wait a été passé ou dois-je employer un moyen de vérification / bouclage de l’attente chronométrée?

Je vous remercie.

Je pourrais toujours créer un statut booléen défini dans le mutex correspondant, mais je ne peux pas effectuer de manière atomique les opérations set et wait en une seule instruction, pour autant que je sache.

C’est la bonne façon de procéder: vous pouvez effectuer une opération set et attendre de manière atomique, en raison de la manière dont les variables de condition interagissent avec les mutex. Lorsque vous effectuez une opération pthread_cond_wait() , le mutex que vous transmettez doit être verrouillé. Si vous avez le même mutex verrouillé lorsque vous effectuez une opération pthread_cond_signal() , le thread en attente ne se réveille pas tant que le thread de signalisation n’a pas déverrouillé le mutex.

Ainsi, le code suivant ferait ce que vous voulez:

 // Flag indicating if the worker thread is waiting or not bool waiting = false; ... // Worker thread code ... do stuff ... while (!condition_is_not_satisfied()) { pthread_mutex_lock(&mutex); waiting = true; pthread_cond_wait(&cond, &mutex); waiting = false; pthread_mutex_unlock(&mutex); } ... // Signalling thread code pthread_mutex_lock(&mutex); if (waiting) { // Worker thread is waiting -- signal it to wake up pthread_cond_signal(&cond); } else { // Worker thread has not yet entered the wait state -- do something else } pthread_mutex_unlock(&mutex); 

Une variable de condition doit toujours être associée à un prédicat protégé par mutex. Dans ce cas, votre prédicat peut être simplement un indicateur: dans le thread de travail, il ressemblerait à ceci:

 pthread_mutex_lock(&mMutex); while (!woken) pthread_cond_wait(&mMutex, &condVar); pthread_mutex_unlock(&mMutex); 

Dans le fil de gestion, cela ressemblerait à:

 pthread_mutex_lock(&mMutex); woken = 1; pthread_cond_signal(&condVar); pthread_mutex_unlock(&mMutex); 

Ici, si le thread gestionnaire acquiert d’abord le mutex, alors, au moment où le travailleur acquiert le mutex, l’indicateur sera défini et il n’attendra pas du tout. si le travailleur acquiert le mutex en premier, le gestionnaire ne pourra pas acquérir le mutex et définir l’indicateur tant que le travailleur n’a pas été retenu au pthread_cond_wait .