web-dev-qa-db-fra.com

Comment les mutex sont-ils mis en œuvre?

Certaines implémentations sont-elles meilleures que d'autres pour des applications spécifiques? Y a-t-il quelque chose à gagner en déployant le vôtre?

53
static_rtti

Consultez la description de l'instruction machine Test-and-set sur Wikipedia, qui fait référence à la façon dont les opérations atomiques sont réalisées au niveau de la machine. Je peux imaginer que la plupart des implémentations de mutex au niveau du langage reposent sur un support au niveau de la machine tel que Test-and-set.

29
Adamski

En vous appuyant sur la suggestion test-and-set D'Adamski, vous devriez également examiner le concept de "mutex rapides de l'espace utilisateur" ou futexes .

Les Futex ont la propriété souhaitable de ne pas nécessiter d'appel système du noyau dans les cas courants de verrouillage ou de déverrouillage d'un mutex non contraint . Dans ces cas, le code en mode utilisateur utilise avec succès une opération atomique comparer et échanger (CAS) pour verrouiller ou déverrouiller le mutex.

Si CAS échoue, le mutex est contesté et un appel système du noyau - sys_futex Sous Linux - doit être utilisé soit pour attendre le mutex (dans le cas de verrouillage) ou pour réveiller d'autres threads (dans le cas de déverrouillage ).

Si vous envisagez sérieusement de l'implémenter vous-même, assurez-vous de lire également papier d'Ulrich Drepper.

22
David Joyner

Un mutex s'exécute de préférence dans le noyau du système d'exploitation tout en gardant la quantité de code qui l'entoure aussi courte que possible, de sorte qu'il peut éviter d'être coupé lors du basculement de tâche vers un autre processus. L'implémentation exacte est donc un peu secrète. Ce n'est pas complexe cependant. C'est fondamentalement un objet qui a un champ booléen, qu'il obtient et définit.

  • Lorsque vous utilisez un compteur, il peut devenir un sémaphore.
  • Un mutex est le point de départ d'une section critique, qui utilise un mutex en interne pour voir s'il peut entrer une section de code. Si le mutex est libre, il définit le mutex et exécute le code, uniquement pour libérer le mutex une fois terminé. Lorsqu'une section critique remarque qu'un mutex est verrouillé, elle peut attendre sa libération.

Autour de la logique mutex de base, il y a des wrappers pour l'envelopper dans un objet. Puis d'autres objets wrapper pour le rendre disponible en dehors du noyau. Et puis un autre wrapper pour le rendre disponible en .NET. Et puis plusieurs programmeurs écriront leur propre code wrapper autour de tout cela pour leurs propres besoins logiques. Les emballages autour des emballages en font vraiment un territoire trouble.

Maintenant, avec ces connaissances de base sur les composants internes des mutex, tout ce que j'espère, c'est que vous allez utiliser une implémentation qui repose sur le noyau et le matériel en dessous. Ce seraient les plus fiables. (Si le matériel les prend en charge.) Si le mutex que vous utilisez ne fonctionne pas à ce niveau noyau/matériel, il peut toujours être fiable, mais je vous conseillerais de ne pas l'utiliser, sauf s'il n'y a pas d'alternative.

Pour autant que je sache, Windows, Linux et .NET utiliseront tous des mutex au niveau du noyau/matériel.

La page Wikipedia à laquelle j'ai lié explique plus sur la logique interne et les implémentations possibles. De préférence, un mutex est contrôlé par le matériel, ce qui rend l'ensemble/obtention du mutex un étape indivisible . (Juste pour vous assurer que le système ne change pas de tâche entre les deux.)

9
Wim ten Brink

Interlocked.CompareExchange est suffisant pour implémenter des verrous tournants. C'est assez difficile à faire correctement. Voir pour le blog de Joe Duffy pour un exemple des subtilités impliquées.

2
Joren

Un peu d'assemblage pour démontrer le verrouillage atomique:

; BL is the mutex id
; shared_val, a memory address

CMP [shared_val],BL ; Perhaps it is locked to us anyway
JZ .OutLoop2
.Loop1:
CMP [shared_val],0xFF ; Free
JZ .OutLoop1 ; Yes
pause ; equal to rep nop.
JMP .Loop1 ; Else, retry

.OutLoop1:

; Lock is free, grab it
MOV AL,0xFF
LOCK CMPXCHG [shared_val],BL
JNZ .Loop1 ; Write failed

.OutLoop2: ; Lock Acquired
1
Michael Chourdakis