Pourquoi ne pthreads’ la variable de condition fonctions nécessitent un mutex?
Je suis en train de lire sur pthread.h
; la variable de condition fonctions connexes (comme pthread_cond_wait(3)
) nécessitent un mutex comme argument. Pourquoi? Aussi loin que je peux dire, je vais créer un mutex juste pour l'utiliser comme argument? Qu'est-ce que ce mutex censé faire?
Vous devez vous connecter pour publier un commentaire.
C'est juste la manière que les variables de condition sont (ou ont été initialement mises en œuvre.
Le mutex est utilisé pour protéger de la variable de condition elle-même. C'est pourquoi vous avez besoin verrouillé avant de vous faire attendre.
L'attente "atomiquement" déverrouille le mutex, permettant à d'autres d'accéder à la variable d'état (pour la signalisation). Puis, lorsque la variable de condition est signalée ou diffusion, un ou plusieurs des fils sur la liste d'attente sera réveillé et le mutex sera magiquement à nouveau verrouillé pour que le thread.
L'on voit habituellement à la suite de l'opération avec les variables de condition, illustrant la façon dont ils travaillent. L'exemple suivant est un thread de travail qui est donné par l'intermédiaire d'un signal à une variable de condition.
Le travail est effectué à l'intérieur de cette boucle, à condition qu'il est disponible lorsque la file d'attente des retours. Lorsque le thread a été signalé à cesser de travailler (généralement par un autre thread réglage de la sortie à l'état de donner des coups de pied de la variable de condition pour réveiller ce fil), la boucle de sortie, le mutex sera débloqué et ce fil sera de sortie.
Le code ci-dessus est un modèle de consommation que le mutex reste bloqué alors que le travail est fait. Pour un multi-consommation variation, vous pouvez utiliser, par exemple:
qui permet à d'autres consommateurs de recevoir un travail alors que celui-ci est en train de faire le travail.
De la variable de condition vous libère du fardeau de l'interrogation de certains état au lieu permettant à un autre thread pour vous avertir lorsque quelque chose doit arriver. Un autre thread peut dire que le thread de travail est disponible comme suit:
La grande majorité de ce qui est souvent appelé à tord fallacieux de réveil est généralement toujours parce que plusieurs threads avait été signalé au sein de leur
pthread_cond_wait
appel (broadcast), on serait de retour avec le mutex, faire le travail, puis re-attendre.Puis la deuxième signalé thread pourrait sortir quand il n'y avait pas de travail à faire. Donc, vous avez dû avoir une variable supplémentaire indiquant que le travail doit être fait (c'était intrinsèquement mutex-protégé avec le condvar/mutex paire ici - d'autres threads nécessaire pour verrouiller le mutex avant de le changer, cependant).
Il était techniquement possible pour un fil de retour d'un état d'attente sans être frappé par un autre processus (c'est une vraie fausse de réveil), mais, dans tous mes nombreuses années de travail sur les pthreads, à la fois dans le développement/service de la code et en tant qu'utilisateur d'eux, je n'ai jamais reçu un de ces. Peut-être que c'était juste parce que HP a fait une bonne mise en œuvre 🙂
Dans tous les cas, le même code, qui traite les erronée cas également traitées de véritables parasites de réveils ainsi depuis les travaux disponibles du drapeau ne seraient pas pour ceux.
do something
à l'intérieur de lawhile
boucle?pthread_cond_signal()
ing contre elle, à cause de l'un de ceux qui de se réveiller et prendre un morceau de travail.Features of Mutexes and Condition Variables
Une variable de condition est assez limité si seulement vous pouviez être le signal d'un état, en général, vous devez gérer certaines données qui sont liées à la condition qui a été signalée. Signalisation/réveil, doivent être faites de manière atomique en ce qui concerne réaliser que sans l'introduction de conditions de course, ou être trop complexe
pthreads peut aussi vous donner , plutôt pour des raisons techniques, un fallacieux de réveil . Cela signifie que vous avez besoin de vérifier un prédicat, de sorte que vous pouvez être sûr que l'état de fait a été signalé - et la distinction que d'une fausse réveil. La vérification de cette condition en ce qui concerne attend-il besoin d'être gardés donc une variable de condition a besoin d'un moyen de atomiquement attendre/réveil lors du verrouillage/déverrouillage d'un mutex préserver cette condition.
Prenons un exemple simple où vous êtes informé que les données sont produites. Peut-être un autre thread fait certaines des données que vous souhaitez et de définir un pointeur vers les données.
Imaginer un producteur de fil en donnant quelques données sur un autre thread consommateur par le biais d'un 'some_data'
pointeur.
vous feriez naturellement beaucoup de course a condition, que si l'autre thread n'a
some_data = new_data
juste après que vous avez obtenu de se réveiller, mais avant que vous nedata = some_data
Vous ne peut pas vraiment créer votre propre mutex pour garder ce cas non plus .e.g
Ne fonctionnera pas, il y a encore une chance d'une condition de concurrence entre le réveil et le saisissant le mutex. Placer le mutex avant la pthread_cond_wait ne vous aide pas, comme vous maintenant
maintenez le mutex en attendant - à-dire le producteur ne sera jamais en mesure de saisir le mutex.
(remarque, dans ce cas, vous pourriez créer une seconde variable d'état de signal pour le producteur que vous avez terminé avec
some_data
- bien que cela va devenir complexe, surtout si vous voulez que de nombreux producteurs/consommateurs.)Donc vous avez besoin d'un moyen de atomiquement de presse/saisir le mutex en attente/le réveil de la condition. C'est ce que pthread les variables de condition, et voici ce que vous devriez faire:
(le producteur serait naturellement besoin de prendre les mêmes précautions, toujours de gardiennage 'some_data" avec le même mutex, et de faire en sorte qu'il n'écrase pas some_data si some_data est actuellement != NULL)
while (some_data != NULL)
être un do-while boucle de sorte qu'il attend de la variable de condition, au moins une fois?while(some_data != NULL)
êtrewhile(some_data == NULL)
?POSIX variables de condition sont apatrides. Donc, il est de votre responsabilité de maintenir l'état. Étant donné que l'état sera accessible par les deux threads qui attendent que le nombre de threads et que dire des autres threads arrêter d'attendre, il doit être protégée par un mutex. Si vous pensez que vous pouvez utiliser des variables de condition, sans un mutex, alors vous n'avez pas compris que les variables de condition sont apatrides.
Les variables de Condition sont construits autour d'un état. Les Threads en attente sur une variable de condition sont en attente d'une condition. Les Threads que le signal de variables de condition de modifier cette condition. Par exemple, un thread peut être en attente pour certains de données pour arriver. Un autre thread peut remarquer que les données sont arrivées. "Les données sont arrivées" est la condition.
Ici est l'utilisation classique d'une variable de condition, simplifié:
Voir comment le thread est en attente pour le travail. L'œuvre est protégée par un mutex. L'attente libère le mutex, de sorte qu'un autre thread puisse donner à ce fil un peu de travail. Voici comment il serait signalé:
Avis que vous besoin le mutex pour protéger la file d'attente de travail. Notez que la variable d'état lui-même n'a aucune idée si il y a du travail ou pas. C'est, une variable de condition doit être associés à une condition, que la condition doit être maintenu par votre code, et depuis il est partagé entre les threads, elle doit être protégée par un mutex.
Pas tous de la variable de condition fonctions nécessitent un mutex: seule l'attente des opérations à faire. Le signal et de l'émission des opérations ne nécessitent pas un mutex. Une variable de condition n'est pas associée de façon permanente avec un mutex spécifique; l'externe mutex ne protège pas de la variable de condition. Si une condition variable d'état interne, comme une file d'attente des threads en attente, ce doit être protégé par un verrou interne à l'intérieur de la variable de condition.
L'attente des opérations de réunir une variable de condition et un mutex, parce que:
Pour cette raison, l'opération d'attente prend comme arguments à la fois le mutex et de l'état: de sorte qu'il peut gérer le transfert atomique d'un fil de posséder le mutex de l'attente, de sorte que le thread ne pas tomber victime de la perdu de réveil condition de course.
La perte d'un réveil à condition de concurrence se produit si un thread donne un mutex, puis attend une apatrides de la synchronisation de l'objet, mais d'une manière qui n'est pas atomique: il existe une fenêtre de temps où le thread n'a plus la serrure, et n'a pas encore commencé en attente sur l'objet. Au cours de cette fenêtre, un autre thread peut venir dans, faire l'attendu condition vrai, le signal de la apatrides de synchronisation et puis disparaissent. Les apatrides objet n'oubliez pas qu'il a été signalé (il est apatride). Alors que le thread d'origine va dormir sur le apatrides de la synchronisation de l'objet, et ne pas se réveiller, même si elle a déjà devenir réalité: perdu réveil.
De la variable de condition attendre fonctions d'éviter les perdus de réveil par faire en sorte que le thread appelant est enregistré de manière fiable attraper le réveil avant qu'il abandonne le mutex. Ce serait impossible si l'état variable en fonction d'attente n'a pas pris le mutex comme un argument.
pthread_cond_broadcast
etpthread_cond_signal
opérations (que ce DONC, la question est sur) ne prennent même pas le mutex comme argument; seulement la condition. POSIX spec est ici. Le mutex est seulement mentionnée en référence à ce qui se passe dans les threads en attente quand ils se réveillent.Je ne trouve pas les autres réponses pour être aussi concis et facile à lire que cette page. Normalement, l'attente, le code ressemble à ceci:
Il y a trois raisons pour envelopper le
wait()
dans un mutex:signal()
avant lawait()
et nous rater ce réveil.check()
dépend de la modification d'un autre thread, si vous avez besoin d'exclusion mutuelle sur elle de toute façon.Le troisième point n'est pas toujours une source de préoccupation - le contexte historique est accessible à partir de l'article de cette conversation.
Fausse wake-up est souvent évoqué à l'égard de ce mécanisme (c'est à dire le thread en attente est réveillé sans
signal()
être appelé). Toutefois, ces événements sont gérés par la bouclecheck()
.Les variables de Condition sont associées à un mutex parce que c'est la seule façon d'éviter la course qu'il est conçu pour éviter.
À ce point, il n'y a pas de fil qui va du signal de la variable de condition, de sorte thread1 attendra toujours, même si le protectedReadyToRunVariable dit qu'il est prêt à aller!
La seule façon de contourner cela est pour les variables de condition de atomiquement libérer le mutex, tout en commençant à attendre sur la variable de condition. C'est pourquoi le cond_wait fonction nécessite un mutex
Le mutex est censé être verrouillé lorsque vous appelez
pthread_cond_wait
; quand vous l'appelez, il atomiquement les deux déverrouille le mutex, puis se bloque sur la condition. Une fois que le problème est signalé, il atomiquement ce qu'il se verrouille à nouveau et retourne.Cela permet la mise en œuvre de la prévisibilité de la planification si vous le souhaitez, en ce que le fil qui ferait de la signalisation peut attendre jusqu'à ce que le mutex est libéré pour effectuer son traitement et signaler l'état.
J'ai fait un exercice en classe, si vous voulez un exemple réel de la variable de condition :
Il semble être une conception spécifique de décision plutôt que conceptuelle besoin.
Par les pthreads docs la raison que le mutex n'a pas été séparés est qu'il y a une amélioration significative de la performance en combinant entre eux et ils attendent que la raison de conditions de course si vous n'utilisez pas un mutex, c'est presque toujours va être fait de toute façon.
https://linux.die.net/man/3/pthread_cond_wait
Il y a des tonnes d'exégèses à ce sujet, mais je veux incarner avec un exemple qui suit.
Quel est le problème avec l'extrait de code? Juste réfléchir un peu avant d'aller de l'avant.
La question est vraiment subtile. Si le parent appelle
thr_parent()
et puis, les vétérinaires, la valeur dedone
, il va voir qu'il est0
etdonc essayer d'aller dormir. Mais juste avant d'appeler attendre d'aller dormir, le parent
est interrompu entre les lignes de 6-7, et l'enfant s'exécute. L'enfant des changements de la variable d'état
done
à1
et des signaux, mais pas de thread est en attente et donc pas de threadréveillé. Lorsque le parent se présente à nouveau, elle dort toujours, qui est vraiment flagrant.
Que si elles sont réalisées alors que les verrous acquis individuellement?