Nicht blockierende Verriegelung

8

Ich möchte einige neue Threads für jeweils eine wiederholte Operation starten. Aber wenn eine solche Operation bereits ausgeführt wird, möchte ich die aktuelle Aufgabe verwerfen. In meinem Szenario brauche ich nur sehr aktuelle Daten - gelöschte Daten sind kein Problem.

In der MSDN habe ich die Mutex -Klasse gefunden, aber wie ich es verstehe, wartet sie auf ihren Zug und blockiert den aktuellen Thread. Auch ich möchte Sie fragen: Gibt es schon etwas im .NET Framework, das das folgende macht:

  1. Wird eine Methode M bereits ausgeführt?
  2. Wenn ja, return (und lassen Sie mich einen Zähler für Statistiken erhöhen)
  3. Wenn nicht, starten Sie Methode M in einem neuen Thread
DerMike 09.02.2012, 10:58
quelle

4 Antworten

23

Die lock(someObject) -Anweisung, auf die Sie vielleicht gestoßen sind, ist syntaktischer Zucker um Monitor.Enter und Monitor.Exit .

Wenn Sie den Monitor jedoch auf diese ausführlichere Weise verwenden, können Sie auch Monitor.TryEnter verwenden, mit dem Sie überprüfen können, ob Sie die Sperre erhalten können - also prüfen, ob jemand sie bereits hat und ausführt Code.

Also statt dessen:

%Vor%

probiere dies (Option 1) :

%Vor%

(Sie werden wahrscheinlich versuchen ... endgültig dort hinein, um sicherzustellen, dass die Sperre freigegeben wird)

oder verzichten Sie auf die explizite Sperre und machen Sie dies

(Option 2)

%Vor%

[Edit: als Antwort auf Ihre Frage zu this ]

Nein - verwenden Sie nicht this bis lock on. Erstellen Sie ein privat definiertes Objekt, das als Ihre Sperre fungiert.

Sonst haben Sie dieses potentielle Problem:

%Vor%

Im obigen Beispiel ist es einem externen Code gelungen, die interne Sperrung unserer Klasse zu unterbrechen, indem nur eine Sperre für etwas entfernt wurde, auf das extern zugegriffen werden konnte.

Es ist viel besser, ein privates Objekt zu erstellen, das Sie kontrollieren und auf das niemand außerhalb Ihrer Klasse Zugriff hat, um diese Art von Problemen zu vermeiden. Dies beinhaltet, dass this oder der Typ selbst typeof(MyClassWithLockInside) zum Sperren nicht verwendet wird.

    
Rob Levine 09.02.2012, 11:17
quelle
2

Eine Möglichkeit wäre, mit einem Reentrancy-Sentinel zu arbeiten:

Sie könnten ein int -Feld definieren (mit 0 initialisieren) und es über Interlocked.Increment bei der Eingabe der Methode und nur weitermachen, wenn es 1 ist. Am Ende tun Sie einfach eine Interlocked.Decrement .

Eine andere Option:

Aus Ihrer Beschreibung geht hervor, dass Sie ein Producer-Consumer-Szenario haben ...

In diesem Fall könnte es hilfreich sein, so etwas wie BlockingCollection zu verwenden fadensicher und meist sperrfrei ...

Eine andere Option wäre die Verwendung von ConcurrentQueue oder ConcurrentStack ...

    
Yahia 09.02.2012 11:19
quelle
1

Auf der folgenden Website finden Sie möglicherweise nützliche Informationen (der PDf ist auch herunterladbar - kürzlich heruntergeladen es selbst). Die Kapitel "Suspend and Resume" oder "Aborting" des Threads "Advanced Threading" sind möglicherweise etwas, an dem Sie interessiert sind.

    
Ctrl_Alt_Defeat 09.02.2012 11:16
quelle
0

Sie sollten die atomaren Operationen der Interlocked-Klasse verwenden - für die beste Leistung, da Sie keine Sychronisierungen auf Systemebene verwenden werden (jede "Standard" -Verknüpfung benötigt sie und beinhaltet einen Systemaufruf-Overhead). // einfacher nicht-reentranter Mutex ohne Eigentümer, einfach remake um // diese Funktionen zu unterstützen (setze den Besitzer nach dem Erwerb der Sperre (vergleiche Threadreferenz mit Thread.CurrentThread zum Beispiel), und überprüfe auf übereinstimmende Identität, addiere Zähler für Reentrancy) // kann bool nicht verwenden, da es von CompareExchange nicht unterstützt wird private int Sperre;

%Vor%     
Mastermind 29.08.2015 05:05
quelle

Tags und Links