Warum muss das Sperrobjekt statisch sein?

112

Es ist sehr üblich, ein privates statisches schreibgeschütztes Objekt zum Sperren von Multithreading zu verwenden. Ich verstehe, dass privat die Eintrittspunkte zum Sperrobjekt reduziert, indem die Kapselung verschärft wird und daher auf das Wesentlichste zugegriffen wird.

Aber warum statisch?

private static readonly object Locker = new object();

Am Ende wird das Feld nur in meiner Klasse verwendet, und ich könnte stattdessen auch nur Folgendes verwenden:

private readonly object Locker = new object();

Irgendwelche Kommentare?

AKTUALISIEREN:

Als Beispiel habe ich diesen Code eingefügt (nur ein Beispiel). Ich könnte ein statisches oder nicht statisches Schließfach verwenden und beide würden gut funktionieren. In Anbetracht der folgenden Antwort sollte ich mein Schließfach eher so definieren? (Entschuldigung, ich habe nächste Woche ein Interview und muss jedes Detail kennen :)

private readonly object Locker = new object();

Und hier ist der Code:

    private int _priceA;
    private int _priceB;
    private EventWaitHandle[] _waithandle;
    private readonly IService _service;

//ctor
public ModuleAViewModel(IService service)
    {
        _service = service;
        _modelA = new ModelA();
        _waithandle = new ManualResetEvent[2];
        _waithandle[0] = new ManualResetEvent(false);
        _waithandle[1] = new ManualResetEvent(false);
        LoadDataByThread();
    }


 private void LoadDataByThread()
        {
            new Thread(() =>
                           {
                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceA = _service.GetPriceA();
                                   }
                                   _waithandle[0].Set();
                               }).Start();

                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceB = _service.GetPriceB();
                                   }
                                   _waithandle[1].Set();
                               }).Start();

                               WaitHandle.WaitAll(_waithandle);
                               PriceA = _priceA;
                               PriceB = _priceB;
                           }).Start();
        }

Vielen Dank

Houman
quelle
15
Meines Wissens wird statisch normalerweise verwendet, um es instanzunabhängig zu machen. Wenn mehrere Instanzen von "MyWorkerClass" vorhanden sind, kann jeweils nur eine mit den angegebenen Daten ausgeführt werden (vorausgesetzt, alle verwenden gemeinsam genutzte Ressourcen).
Brad Christie
2
Der Bearbeitung fehlt ein wichtiges Detail: Wo sind _serviceund befinden _waithandlesich? Beispiel? statisch? andere? Das könnte zum Beispiel sein, dass der Zugriff auf einen Remote-Server absichtlich synchronisiert wird ...
Marc Gravell
Richtig, mit der zweiten Bearbeitung: Ja, von diesem Ende der Dinge könnten Sie pro Instanz sperren. Es kann jedoch Gründe gegeben haben, es statisch zu machen - wenn der ursprüngliche Entwickler (wie erwähnt) den Zugriff synchronisieren wollte, damit der Server nur eine Anfrage gleichzeitig von dieser AppDomain erhält ... Ich kann nicht wissen, ob dies der Fall ist oder ob es nur ein Zufall war.
Marc Gravell

Antworten:

177

Es ist nicht "sehr üblich, ein privates statisches schreibgeschütztes Objekt zum Sperren in Multithreading zu verwenden", sondern es ist üblich, eine Sperre mit der entsprechenden / gewählten Granularität zu verwenden . Manchmal ist das so static. Meistens, IMO, ist es nicht - aber es ist instanzbasiert .

Die Hauptzeit, in der Sie eine staticSperre sehen, ist für einen globalen Cache oder für das verzögerte Laden globaler Daten / Singletons. Und in letzterem gibt es sowieso bessere Möglichkeiten .

Es kommt also wirklich darauf an: Wie wird Lockeres in Ihrem Szenario verwendet? Schützt es etwas, das selbst statisch ist? In diesem Fall sollte das Schloss statisch sein. Wenn es etwas zu schützen , die ist Instanz basiert, dann IMO sollte die Sperre auch Instanz basiert.

Marc Gravell
quelle
24
Könnten Sie näher erläutern, wie das Laden globaler Daten besser verzögert werden kann?
Bizi
Ich verwende immer ein statisches / flüchtiges Element, da ich, wenn es mehrere Stellen gibt, an denen es instanzbasiert ist, trotzdem den Zugriff auf meine Methode / Variable auf threadsichere Weise steuern möchte. Viele Instanzen greifen möglicherweise auf dieselben Ressourcen zu, und ich möchte dies steuern. Auch ich würde gerne sehen, wie es besser ist. Sie haben einen großartigen Repräsentanten und ich bin sicher, dass Ihre Antwort für mich ebenso großartig sein wird. Bitte antworte?
Andrew Simpson
82

Es muss nicht statisch sein, manchmal sollte es auch nicht statisch sein.

Die Variable sollte sich im selben Bereich befinden wie die Methoden, mit denen Sie sie zum Sperren verwenden. Wenn die Methoden statisch sind, sollte die Variable statisch sein, und wenn die Methoden Instanzmethoden sind, sollte die Variable eine Instanzvariable sein.

Eine statische Variable funktioniert weiterhin, wenn sie zum Sperren einer Instanzmethode verwendet wird, aber dann werden Sie zu viel sperren. Sie sperren alle Methoden in allen Instanzen, nicht nur die Methoden in derselben Instanz.

Guffa
quelle
28
+1 für das "a-ha" ... Sie sperren alle Methoden in allen Instanzen, nicht nur die Methoden in derselben Instanz.
Radarbob
3
@radarbob - Kleinere Details: Sie werden nicht alle Methoden sperren, sondern nur eine Sperre, an der mehr Clients interessiert sein könnten. Methoden werden nie gesperrt, nur dass der Mutex verwendet wurde.
Erno
Ich vermute, dass die Formulierung dieser Antwort irreführend sein könnte - das Sperren sollte nichts mit dem Umfang der Methoden zu tun haben - es sollte sich nur mit dem Umfang der gemeinsam genutzten Daten befassen, auf die in diesen Methoden zugegriffen wird. Die
Instanzmethode greift
@AlexeiLevenkov: Sie haben Recht, dass der Umfang tatsächlich davon abhängen sollte, ob die Daten statisch sind oder nicht, aber der Umfang der Methoden sollte auch davon bestimmt werden, damit alles zusammenpasst. Instanzdaten müssen normalerweise nicht gesperrt werden. Wenn die Instanz jedoch von mehreren Threads gemeinsam genutzt wird, müssen Sie gesperrt werden.
Guffa
28

Der Umfang und die Lebensdauer eines Schlosses können / sollten von dem 'Ding' abhängen, das Sie sperren möchten. Statische Sperren werden meistens verwendet, um statische Dinge zu sperren.

Erno
quelle
3
Kleinere Details: Die Sperre ist nicht statisch. Das Objekt, mit dem Sie die Sperre identifizieren, ist statisch. Ein weiteres kleines Detail: Sie sperren keine "Dinge".
Guffa
2
Ja, ich denke, wenn wir versuchen würden, die falschen "Dinge" einzusperren, könnten sie zu groß und stark sein und eines Tages entkommen.
ProfK
12
@Guffa Das ist seltsam, in einem Kommentar oben haben Sie zu Recht gesagt: "Sie sind nur überkompliziert", jetzt sehe ich 1 Minute bevor ich das sage, es scheint, Sie haben Dinge überkompliziert :)
Nicholas Petersen