2013-02-26 3 views
11

Lorsqu'un mutex est déjà verrouillé par T1 et que T2 tente de le verrouiller, quel est le processus pour T2?Implémentation et signalisation Mutex

Je pense qu'il ressemble à ceci:

-T2 essaie de verrouiller, échoue, spinlocks peut-être un peu, puis appelle le rendement ...
-T2 est prévu pour l'exécution d'une ou deux fois, essaie de verrouiller tombe en panne, les rendements ...
-Finalement T1 déverrouille, T2 doit être exécuté et parvient à verrouiller le mutex ...

-t-T1 déverrouillage signalent explicitement au programmateur ou d'autres fils que le mutex est déverrouillé? Ou tout simplement déverrouiller, et laisser le planificateur de planifier des threads bloqués quand il le juge approprié (aka scheduler n'a aucune notion de threads bloqués et ne les traite pas comme spéciaux)?

+1

Je pense que le principe d'exclusion mutuelle garantit qu'aucun 2 threads ou plus ne pénètrent dans la section critique en même temps. Maintenant, si vous avez une file d'attente pour les threads qui tentent de verrouiller le mutex ou si vous faites juste un busy, attendez qu'un mutex soit libre dépend de la façon dont vous l'implémentez et quels sont vos besoins en mutex. Par exemple, 'mutex' dans RTOS comme VxWorks implémente le protocole de plafond prioritaire, dont vous n'avez pas besoin dans le système d'exploitation généraliste (GPOS). – Raj

Répondre

3

En bref: oui, peut-être ...

Ce sont des détails de mise en œuvre, et il est assez difficile de dire sans au moins savoir quels système d'exploitation que vous parlez. En règle générale, le déverrouillage d'un mutex marquera uniquement le thread en attente comme «exécutable», mais n'invoquera pas (nécessairement) le planificateur à ce moment-là - et même si le planificateur est appelé, cela ne signifie pas que T2 sera le prochain thread courir.

Sous Linux, le code entre mutex_unlock() qui vérifie s'il y a une tâche en attente (en vérifiant si le nombre de verrous est inférieur à zéro - il commence à 1 pour déverrouillé, une seule demande de verrou le met à zéro, une nouvelle tentative de verrouillage le rendra négatif). S'il y a un autre processus d'attente, il appelle un «slow path unlock», qui via deux fonctions de redirection pour permettre les détails de mise en œuvre, se termine par __mutex_unlock_common_slowpath - quelques lignes plus bas, il y a un appel à wake_up_process qui finit par se terminer dans try_to_wake_up - qui met simplement la tâche en file d'attente comme "prêt à fonctionner", puis appelle le planificateur (via plusieurs couches de fonctions!)

+0

donc vous dites que sur Linux thread qui bloque est marqué comme non exécutable (donc sched ne le programme pas avant qu'il ne soit marqué comme runable) – NoSenseEtAl

+0

Oui, c'est correct. Cela suppose que vous utilisez le noyau mutex tho ', qui peut ne pas être ce que, par exemple, pthread_mutex implémente. –

+0

très bonne réponse ... btw sans moi vous dérange beaucoup ... pouvez-vous dire rapidement si le futex diffère de cela de manière significative. – NoSenseEtAl

6

Cela dépend de votre système d'exploitation. J'ai vu juste tourner, tourner avec yield, les variables d'état générales dans le noyau, la programmation contrôlée par l'utilisateur et les primitives de verrouillage spécialisées avec le support du noyau.

Le filage et le filage avec yield ont des performances terribles. Théoriquement la programmation contrôlée par les utilisateurs (voir Scheduler activations) devrait avoir les meilleures performances, mais pour autant que je sache, personne ne l'a jamais fait fonctionner correctement dans tous les cas. Les variables de condition générales dans le noyau et les primitives de verrouillage spécialisées avec support du noyau devraient être plus ou moins les mêmes avec futex dans Linux comme le meilleur exemple de ce dernier.

Il existe des situations où le filage peut avoir de meilleures performances. Dans Solaris, une primitive de verrouillage du noyau a un mode adaptatif dans lequel le verrou tourne tant que le processus qui maintient le verrou fonctionne sur un processeur différent. Si le propriétaire de l'écluse dort ou obtient préempté le serveur de verrouillage s'endort également. Dans les autres noyaux, il y a des classes de serrures où le propriétaire du verrou ne peut pas être préempté ou dormir lorsqu'il tient la serrure, alors dans ces cas-là le filage fonctionne bien aussi. En général cependant, en particulier dans le domaine des utilisateurs, le spinning a des cas dégénérés horribles (le processus de rotation tourne jusqu'à ce qu'il soit préempté de laisser le propriétaire du verrou courir) que c'est très mauvais pour la performance. Notez que les primitives de verrouillage spécialisées comme futex peuvent implémenter des optimisations comme celles-ci, ce que les variables de condition générales ne peuvent normalement pas faire.

+0

gentil A, mais "Spinning et spinning avec rendement ont des performances terribles" devrait être qualifié ... Je peux imaginer des scénarios de faible contention et de faible quantité de travail sous verrou où les spinlocks sont rapides. – NoSenseEtAl

+1

TOUS les verrous sont (assez) efficaces lorsqu'il n'y a pas de conflit. Des méthodes de verrouillage bien conçues sont ÉGALEMENT efficaces en cas de conflit élevé. Cela dépend aussi du nombre de processeurs disponibles - une attente "tournante" est terrible sur un système de processeur unique, parce que l'autre thread qui détient actuellement le verrou ne fonctionnera pas, et T2 utilise tout le CPU pour vérifier si T1 qui n'est pas en train d'exécuter a libéré le verrou - c'est l'utilisation plutôt inutile du temps CPU. –

+0

@Mats Je pensais au système multicœur, mais je suis d'accord avec vous pour le noyau unique. – NoSenseEtAl

1

Disons que nous avons suivant le scénario:

1. T1 got M1. M1 locked. 
2. T2 tries to get M1 and gets blocked as M1 is locked. 
3. T3 tries to get M1 and gets blocked as M1 is locked. 
4. ...some time later... 
5. T1 unlocks M1.* 
6. T2 got M1. 
7. T3 is unblocked and tries to get M1 but is blocked again as T2 got M1 first. 

* L'appel système, déverrouillage, doit informer tous bloqué tâches/processus/threads qui sont bloqués sur appel de verrouillage du mutex . Ils sont ensuite planifiés pour exécution. Cela ne signifie pas qu'ils sont exécutés car il pourrait déjà y avoir quelqu'un en exécution. Comme d'autres l'indiquent, cela dépend de la mise en œuvre. Comment cela se fait-il? Si vous voulez vraiment apprendre aussi bien, je recommanderais ceci book

Questions connexes