Kann jemand den Unterschied erklären zwischen:
- lock (ein Objekt) {}
- Mutex verwenden
- Semaphor verwenden
- Monitor verwenden
- Verwenden anderer .Net-Synchronisationsklassen
Ich kann es einfach nicht herausfinden. Es scheint mir, dass die ersten beiden gleich sind?
c#
multithreading
synchronization
locking
mutex
user38834
quelle
quelle
Antworten:
Gute Frage. Ich liege vielleicht falsch. Lassen Sie mich versuchen. Revision Nr. 2 meiner ursprünglichen Antwort. Mit etwas mehr Verständnis. Danke, dass du mich zum Lesen gebracht hast :)
lock (obj)
Monitore
Die Verwendung von Monitor wird im Allgemeinen Mutexen vorgezogen, da Monitore speziell für .NET Framework entwickelt wurden und daher Ressourcen besser nutzen.
Die Verwendung einer Sperre oder eines Monitors ist nützlich, um die gleichzeitige Ausführung von threadsensitiven Codeblöcken zu verhindern. Diese Konstrukte ermöglichen es jedoch nicht, dass ein Thread ein Ereignis an einen anderen kommuniziert. Dies erfordert Synchronisationsereignisse , bei denen es sich um Objekte mit einem von zwei signalisierten und nicht signalisierten Zuständen handelt, mit denen Threads aktiviert und angehalten werden können. Mutex, Semaphore sind Konzepte auf Betriebssystemebene. Beispiel: Mit einem benannten Mutex können Sie mehrere (verwaltete) Exes synchronisieren (um sicherzustellen, dass nur eine Instanz Ihrer Anwendung auf dem Computer ausgeführt wird.)
Mutex:
Semaphoren (verletzen mein Gehirn).
DIE ZU LESENDE SEITE - Thread-Synchronisation (C #)
quelle
Monitor
die Kommunikation nicht zulässig ist. Sie können nochPulse
usw. mit einemMonitor
Zu "Verwenden anderer .Net-Synchronisationsklassen" - einige der anderen, die Sie kennen sollten:
Es gibt auch mehr (niedrige Overhead-) Sperrkonstrukte in CCR / TPL ( Parallel Extensions CTP) - aber IIRC, diese werden in .NET 4.0 verfügbar gemacht
quelle
Wie in ECMA angegeben und wie Sie anhand der Reflected-Methoden beobachten können, entspricht die lock-Anweisung im Wesentlichen
Aus dem oben genannten Beispiel geht hervor, dass Monitore Objekte sperren können.
Mutexe sind nützlich, wenn Sie eine Interprozesssynchronisation benötigen, da sie eine Zeichenfolgenkennung sperren können . Dieselbe Zeichenfolgenkennung kann von verschiedenen Prozessen verwendet werden, um die Sperre zu erhalten.
Semaphoren sind wie Mutexe auf Steroiden. Sie ermöglichen den gleichzeitigen Zugriff, indem sie eine maximale Anzahl gleichzeitiger Zugriffe ermöglichen. Sobald das Limit erreicht ist, blockiert das Semaphor den weiteren Zugriff auf die Ressource, bis einer der Aufrufer das Semaphor freigibt.
quelle
Ich habe die Klassen- und CLR-Unterstützung für das Threading in DotGNU durchgeführt und habe ein paar Gedanken ...
Sofern Sie keine prozessübergreifenden Sperren benötigen, sollten Sie die Verwendung von Mutex & Semaphoren immer vermeiden. Diese Klassen in .NET sind Wrapper für Win32 Mutex und Semaphoren und ziemlich schwer (sie erfordern einen Kontextwechsel in den Kernel, der teuer ist - insbesondere, wenn Ihre Sperre nicht umstritten ist).
Wie bereits erwähnt, ist die C # -Sperranweisung Compiler-Magie für Monitor.Enter und Monitor.Exit (vorhanden innerhalb eines try / finally).
Monitore verfügen über einen einfachen, aber leistungsstarken Signal- / Wartemechanismus, den Mutexe über die Monitor.Pulse / Monitor.Wait-Methoden nicht haben. Das Win32-Äquivalent wären Ereignisobjekte über CreateEvent, die tatsächlich auch in .NET als WaitHandles vorhanden sind. Das Pulse / Wait-Modell ähnelt Unixs pthread_signal und pthread_wait, ist jedoch schneller, da es sich im unbestrittenen Fall vollständig um Operationen im Benutzermodus handeln kann.
Monitor.Pulse / Wait ist einfach zu bedienen. In einem Thread sperren wir ein Objekt, überprüfen ein Flag / einen Status / eine Eigenschaft und rufen Monitor.Wait auf, um die Sperre aufzuheben und zu warten, bis ein Impuls gesendet wird. Wenn die Wartezeit zurückkehrt, kehren wir zurück und überprüfen das Flag / den Status / die Eigenschaft erneut. Im anderen Thread sperren wir das Objekt, wenn wir das Flag / den Status / die Eigenschaft ändern, und rufen dann PulseAll auf, um alle abhörenden Threads zu aktivieren.
Oft möchten wir, dass unsere Klassen threadsicher sind, also setzen wir Sperren in unseren Code. Es ist jedoch häufig der Fall, dass unsere Klasse immer nur von einem Thread verwendet wird. Dies bedeutet, dass die Sperren unseren Code unnötig verlangsamen. Hier können clevere Optimierungen in der CLR dazu beitragen, die Leistung zu verbessern.
Ich bin mir nicht sicher, ob Microsoft Sperren implementiert, aber in DotGNU und Mono wird im Header jedes Objekts ein Sperrstatus-Flag gespeichert. Jedes Objekt in .NET (und Java) kann zu einer Sperre werden, sodass jedes Objekt dies in seinem Header unterstützen muss. In der DotGNU-Implementierung gibt es ein Flag, mit dem Sie eine globale Hashtabelle für jedes Objekt verwenden können, das als Sperre verwendet wird. Dies hat den Vorteil, dass für jedes Objekt ein 4-Byte-Overhead vermieden wird. Dies ist nicht besonders für den Speicher geeignet (insbesondere für eingebettete Systeme, die nicht stark mit Threads versehen sind), beeinträchtigt jedoch die Leistung.
Sowohl Mono als auch DotGNU verwenden effektiv Mutexe, um Sperren / Warten durchzuführen, verwenden jedoch Vergleichs- und Austauschoperationen im Spinlock-Stil , um die Notwendigkeit zu beseitigen, tatsächlich harte Sperren durchzuführen, sofern dies nicht wirklich erforderlich ist:
Hier sehen Sie ein Beispiel, wie Monitore implementiert werden können:
http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup
quelle
Eine zusätzliche Einschränkung beim Sperren eines gemeinsam genutzten Mutex, den Sie mit einer Zeichenfolgen-ID identifiziert haben, besteht darin, dass standardmäßig ein "lokaler \" Mutex verwendet wird und nicht für Sitzungen in einer Terminalserverumgebung freigegeben wird.
Stellen Sie Ihrer Zeichenfolgenkennung "Global \" voran, um sicherzustellen, dass der Zugriff auf freigegebene Systemressourcen ordnungsgemäß gesteuert wird. Ich hatte gerade eine Menge Probleme beim Synchronisieren der Kommunikation mit einem Dienst, der unter dem SYSTEM-Konto ausgeführt wurde, bevor mir dies klar wurde.
quelle
Ich würde versuchen, "lock ()", "Mutex" und "Monitor" zu vermeiden, wenn Sie können ...
Schauen Sie sich den neuen Namespace System.Collections.Concurrent in .NET 4 an.
Er enthält einige nette thread-sichere Auflistungsklassen
http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx
ConcurrentDictionary rockt! Keine manuelle Verriegelung mehr für mich!
quelle
In den meisten Fällen sollten Sie keine Sperren (= Monitore) oder Mutexe / Semaphoren verwenden. Sie alle blockieren den aktuellen Thread.
Und du solltest es definitiv nicht benutzen
System.Collections.Concurrent
Klassen verwenden - sie sind die Hauptursache für Rennbedingungen, da sie keine Transaktionen zwischen mehreren Sammlungen unterstützen und auch den aktuellen Thread blockieren.Überraschenderweise verfügt .NET nicht über effektive Mechanismen zur Synchronisierung.
Ich habe die serielle Warteschlange von GCD (
Objc/Swift
world) auf C # implementiert - ein sehr leichtes, nicht blockierendes Synchronisationstool, das den Thread-Pool verwendet, mit Tests.In den meisten Fällen ist dies der beste Weg, um alles zu synchronisieren - vom Datenbankzugriff (Hallo SQLite) bis zur Geschäftslogik.
quelle