J'ai fait les classes et le support CLR pour le threading dans DotGNU et j'ai quelques réflexions...
À moins que vous n'ayez besoin de verrouillages interprocessus, vous devriez toujours éviter d'utiliser les Mutex et les sémaphores. Ces classes dans .NET sont des enveloppes autour des Mutex et Sémaphores Win32 et sont plutôt lourdes (elles nécessitent un changement de contexte dans le noyau, ce qui est coûteux - surtout si votre verrou n'est pas en conflit).
Comme d'autres l'ont mentionné, l'instruction de verrouillage C# est une magie du compilateur pour Monitor.Enter et Monitor.Exit (existant dans un try/finally).
Les moniteurs ont un mécanisme de signal/attente simple mais puissant que les Mutex n'ont pas via les méthodes Monitor.Pulse/Monitor.Wait. L'équivalent Win32 serait des objets d'événement via CreateEvent qui existent également dans .NET sous la forme de WaitHandles. Le modèle Pulse/Wait est similaire au pthread_signal et au pthread_wait d'Unix, mais il est plus rapide parce qu'il peut s'agir d'opérations entièrement en mode utilisateur dans les cas non-contrôlés.
Monitor.Pulse/Wait est simple à utiliser. Dans un thread, nous verrouillons un objet, vérifions un drapeau/état/propriété et si ce n'est pas ce que nous attendons, nous appelons Monitor.Wait qui va libérer le verrou et attendre qu'une impulsion soit envoyée. Lorsque l'attente revient, nous bouclons et vérifions à nouveau le drapeau/état/propriété. Dans l'autre thread, nous verrouillons l'objet chaque fois que nous changeons le drapeau/état/propriété, puis nous appelons PulseAll pour réveiller tous les threads qui écoutent.
Souvent, nous voulons que nos classes soient thread safe, alors nous mettons des verrous dans notre code. Cependant, il est fréquent que notre classe ne soit utilisée que par un seul thread. Cela signifie que les verrous ralentissent inutilement notre code... c'est là que des optimisations intelligentes dans le CLR peuvent aider à améliorer les performances.
Je ne suis pas sûr de l'implémentation des verrous par Microsoft mais dans DotGNU et Mono, un drapeau d'état de verrouillage est stocké dans l'en-tête de chaque objet. Chaque objet dans .NET (et Java) peut devenir un verrou, donc chaque objet doit le supporter dans son en-tête. Dans l'implémentation de DotGNU, il y a un drapeau qui vous permet d'utiliser une table de hachage globale pour chaque objet qui est utilisé comme un verrou -- cela a l'avantage d'éliminer un overhead de 4 octets pour chaque objet. Ce n'est pas génial pour la mémoire (surtout pour les systèmes embarqués qui ne sont pas fortement threadés) mais cela a un impact sur les performances.
Mono et DotGNU utilisent effectivement les mutex pour effectuer le verrouillage et l'attente mais utilisent un style de spinlock. comparer et échanger afin d'éliminer la nécessité d'effectuer des verrouillages forcés, sauf si cela est vraiment nécessaire :
Vous pouvez voir ici un exemple de la façon dont les moniteurs peuvent être mis en œuvre :
http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup
0 votes
Ce lien m'a beaucoup aidé : albahari.com/filetage