POSIX Threads C. pthread_cond_t exemple. Ne fonctionne pas comme prévu
J'ai écrit un écrit un programme qui ne fonctionne pas comme prévu pour.
J'ai deux fils: thread
déclenche func
et anotherThread
déclenche anotherFunc
. Ce que je voulais faire, c'est quand cont
atteint la valeur 10
dans func
, anotherThread
être déclenché à l'aide de pthread_cond_wait
et pthread_cond_signal
. La chose étrange est que tout fonctionne bien si je décommentez la sleep(1)
ligne. Je suis nouveau sur les threads et j'ai suivi le tutoriel ici et si je commente la sleep
ligne dans leur exemple, il rompt ainsi.
Ma question est comment puis-je faire ce travail sans sleep()
appels? Et qu'advient-il si dans mon code à la fois func
atteint pthread_mutex_lock
après anotherFunc
? Comment puis-je contrôler ces choses? C'est mon code:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t myMutex;
pthread_cond_t cond;
pthread_attr_t attr;
int cont;
void *func(void*)
{
printf("func\n");
for(int i = 0; i < 20; i++)
{
pthread_mutex_lock(&myMutex);
cont++;
printf("%d\n", cont);
if(cont == 10)
{
printf("signal:\n");
pthread_cond_signal(&cond);
// sleep(1);
}
pthread_mutex_unlock(&myMutex);
}
printf("Done func\n");
pthread_exit(NULL);
}
void *anotherFunc(void*)
{
printf("anotherFunc\n");
pthread_mutex_lock(&myMutex);
printf("waiting...\n");
pthread_cond_wait(&cond, &myMutex);
cont += 10;
printf("slot\n");
pthread_mutex_unlock(&myMutex);
printf("mutex unlocked anotherFunc\n");
printf("Done anotherFunc\n");
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t thread;
pthread_t anotherThread;
pthread_attr_init(&attr);
pthread_mutex_init(&myMutex, NULL);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_cond_init(&cond, NULL);
pthread_create(&anotherThread, &attr, anotherFunc, NULL);
pthread_create(&thread, &attr, func, NULL);
pthread_join(thread, NULL);
pthread_join(anotherThread, NULL);
printf("Done MAIN()");
pthread_mutex_destroy(&myMutex);
pthread_cond_destroy(&cond);
pthread_attr_destroy(&attr);
pthread_exit(NULL);
return 0;
}
Désolé pour le long post, mais je suis nouveau sur les threads et je suis disposé à apprendre. Aussi savez-vous quelques bonnes références ou des cours/tutoriels sur les threads et la mise en réseau sur Linux? Je veux apprendre à créer un client de chat et j'ai entendu dire que je sais de threads et de mise en réseau pour que. Le problème est que je ne connais pas assez bon si ce que j'ai appris est ok puisque je ne sais pas ce que je dois savoir.
Merci beaucoup 🙂
- D'autres remarques. J'ai plus de ne pas avoir à utiliser un
pthread_attr_t
, vous pouvez utiliser les initialiseurs statiques pour la condition et les mutex pour simplifier le code. En outre, votre fil fonctions peuvent justereturn NULL;
oureturn 0;
au lieu de l'appelerpthread_exit
. Et votre thread principal peut justereturn 0;
de main sans appelpthread_exit
. Les autres threads ne sont pas en cours d'exécution à ce point, car ils ont été rejoints. de retour de forces principales d'un processus de sortie, maispthread_exit
dans le thread principal ne force pas un processus de sortie, ce qui est utile pour maintenir les autres threads en cours d'exécution. - Aussi, il n'est pas nécessaire de nettoyer statique mutex et les conditions. Utilisez simplement
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
. Le complexe initialisations sont nécessaires pour les situations où vous souhaitez définir des caractéristiques inhabituelles. E. g. faire un processus partagé robuste mutex.
Vous devez vous connecter pour publier un commentaire.
Votre
anotherThread
appelle simplementpthread_cond_wait
sans d'abord vérifier si l'état désiré (compteur atteint dix) a déjà eu lieu. C'est logique incorrecte, ce qui va conduire à la perdu réveil problème: le nom d'un bug récurrent qui sévit mal écrit les programmes multithread.Les variables de Condition sont apatrides. Si
pthread_cond_signal
oupthread_cond_broadcast
est appelée sur un état qui n'a pas de fils sont actuellement en attente, l'opération n'a aucun effet. Il n'est pas souvenu. Il est donc possible pour votre signalisation fil à compter de10
très rapidement, et le signal de la variable de condition, avant que l'autre thread a atteint lepthread_cond_wait
appel.Vous avez besoin d'une boucle autour de
pthread_cond_wait
. La condition doit être vérifiée dans le cas où c'est déjà le cas, de sorte que le fil ne prend pas en attendre un réveil qui a déjà eu lieu. Et il devrait être une boucle parce que les réveils peuvent être faux: tout simplement parce que le fil passe à travers lepthread_cond_wait
ne signifie pas que la condition est en fait vrai:Aussi, il n'est pas nécessaire de créer un attribut du thread juste pour faire un fil recrutables. C'est la situation par défaut lorsque vous utilisez un pointeur null pour la création de l'attribut. POSIX threads sont recrutables sauf créé détaché, ou convertis détaché avec
pthread_detach
.Autre chose: chaque fois que possible, éviter d'appeler
pthread_cond_signal
tout en maintenant un mutex lock. Il n'est pas incorrect, mais c'est potentiellement un gaspillage, car l'opération peut en fait avoir à appeler dans le noyau de système d'exploitation pour réveiller un thread, et si vous êtes en possession de ce cher mutex lock sur l'ensemble du système d'appel (lorsque tous vous avez vraiment besoin d'elle pour se protéger un peu des instructions machine de travailler avec des données partagées dans votre application).Je ne sais pas ce que votre problème est (ce qui se passe quand il ne fonctionne pas?)..
Je vois un problème majeur, vous ne le manipulez pas la les réveils intempestifs.
Vous besoin de quelque chose que les signaux que la condition est vraiment vrai, par exemple avec une variable booléenne:
init:
signal:
recevoir:
if
autour de lapthread_cond_wait
. Les réveils intempestifs sont un problème mineur qui exige que pour être unwhile
. Il est peu probable qu'un faux réveil même se produire dans ce one-shot situation avec seulement deux fils.Ce que vous voulez, c'est un sémaphore pas une variable de condition.
Un sémaphore maintient l'état et compte wait() et les signaux() contre elle.
Il est généralement mis en œuvre à l'aide d'une variable de condition.
Look ici pour une implémentation triviale.
C'est juste une idée mais vous pouvez également utiliser les sémaphores de faire de la "détente". Je me souviens d'un projet que je travaille sur un tout à l'heure et ce que nous avons fait est que, bien que l'un de nos thread est en attente d'être déclenchée (à l'aide d'un sem_wait), il serait tout simplement attendre un temps infini à essayer d'obtenir le verrou (et donc a été prise hors de la proc par le planificateur et économiser de précieux cycles). Une fois que le thread principal était fait faire son calcul, on pourrait libérer le sémaphore permettant le deuxième thread pour faire du calcul.
C'est tout simplement une autre alternative.