C #: Was ist, wenn eine statische Methode von mehreren Threads aufgerufen wird?


93

In meiner Anwendung habe ich eine statische Methode, die von mehreren Threads gleichzeitig aufgerufen wird. Besteht die Gefahr, dass meine Daten verwechselt werden?

Bei meinem ersten Versuch war die Methode nicht statisch und ich habe mehrere Instanzen der Klasse erstellt. In diesem Fall wurden meine Daten irgendwie verwechselt. Ich bin mir nicht sicher, wie das passiert, weil es nur manchmal passiert. Ich debugge immer noch. Aber jetzt ist die Methode statisch. Ich habe bisher keine Probleme. Vielleicht ist es nur Glück. Ich weiß es nicht genau.


Antworten:


96

In Methoden deklarierte Variablen (mit der möglichen Ausnahme von " erfassten " Variablen) sind isoliert, sodass keine inhärenten Probleme auftreten. Wenn Ihre statische Methode jedoch auf einen freigegebenen Status zugreift, sind alle Wetten deaktiviert.

Beispiele für einen gemeinsamen Zustand wären:

  • statische Felder
  • Objekte, auf die aus einem gemeinsamen Cache zugegriffen wird (nicht serialisiert)
  • Daten, die über die Eingabeparameter (und den Status dieser Objekte) abgerufen werden, wenn es möglich ist, dass mehrere Threads dasselbe Objekt berühren.

Wenn Sie einen gemeinsamen Status haben, müssen Sie entweder:

  • Achten Sie darauf, den Status nicht zu mutieren, sobald er gemeinsam genutzt werden kann (besser: Verwenden Sie unveränderliche Objekte, um den Status darzustellen, und erstellen Sie eine Momentaufnahme des Status in einer lokalen Variablen. Wenn Sie also nicht whatever.SomeDatawiederholt referenzieren , lesen Sie whatever.SomeData einmal in eine lokale Variable und dann benutze einfach die Variable - beachte, dass dies nur für den unveränderlichen Zustand hilft!)
  • Synchronisieren Sie den Zugriff auf die Daten (alle Threads müssen synchronisiert werden) - entweder gegenseitig ausschließend oder (detaillierter) Leser / Schreiber

1
@Diego - ist dieser Kommentar für mich oder für @Holli bestimmt?
Marc Gravell

An Holli, nur um Ihrer Antwort einige praktische Informationen hinzuzufügen.
Diego Pereyra

1
@Marc Ich kann nicht vollständig zustimmen mit "Variablen, die innerhalb von Methoden deklariert wurden (mit der möglichen Ausnahme von" erfassten "Variablen), sind isoliert". Stellen Sie sich ein Dateihandle vor, das in einer statischen Methode deklariert ist. Dann kann ein Thread auf das Handle zugreifen, wenn ein anderer Thread es verwendet. Dies führt zu unerwartetem Verhalten. Oder bedeutet Ihre "erfasste" Variable auch "Dateihandle"?
Prabhakaran

9
@prabhakaran Wenn ein Dateihandle eine Methodenvariable ist, ist es nur für diesen Aufrufer gültig . Jeder andere Aufrufer spricht mit einer anderen Variablen (Methodenvariablen sind pro Aufruf). Der Zugriff auf die zugrunde liegende Datei ist ein separates Problem, das jedoch nichts mit c # oder .NET zu tun hat. Wenn das Handle nicht gemeinsam genutzt wird, würde man eine Art Mutex / Sperre erwarten, wenn dieses Szenario wahrscheinlich ist.
Marc Gravell

28

Ja, es ist nur Glück. ;)

Es spielt keine Rolle, ob die Methode statisch ist oder nicht. Entscheidend ist, ob die Daten statisch sind oder nicht.

Wenn jeder Thread eine eigene Instanz der Klasse mit einem eigenen Datensatz hat, besteht keine Gefahr, dass Daten verwechselt werden. Wenn die Daten statisch sind, gibt es nur einen Datensatz, und alle Threads verwenden dieselben Daten, sodass es keine Möglichkeit gibt, sie nicht zu verwechseln.

Wenn Ihre Daten in separaten Instanzen immer noch verwechselt werden, liegt dies höchstwahrscheinlich daran, dass die Daten nicht wirklich getrennt sind.


6
Liebte diese Linie - It doesn't matter if the method is static or not, what matters is if the data is static or not. Nur um hinzuzufügen, die lokalen Variablen, die im Rahmen einer statischen Methode deklariert wurden, bilden nicht den Teil der Daten, um den wir uns im gegebenen Szenario kümmern müssen.
RBT

gute Antwort. Hat mir sehr geholfen.
Fraktal

15

Statische Methoden sollten für mehrere Threads in Ordnung sein.

Statische Daten können andererseits ein Problem verursachen, da Versuche, von verschiedenen Threads auf dieselben Daten zuzugreifen, gesteuert werden müssen, um sicherzustellen, dass jeweils nur ein Thread die Daten liest oder schreibt.


2
Das Schlüsselwort hier ist Synchronisation :-)
G. Stoynev

2
Lesen ist in Ordnung, um gleichzeitig zu geschehen, aber Lesen UND Schreiben gleichzeitig führt zu unerwartetem Verhalten
Freestyle076

9

MSDN sagt immer:

Alle öffentlichen statischen (in Visual Basic freigegebenen) Mitglieder dieses Typs sind threadsicher. Es wird nicht garantiert, dass Instanzmitglieder threadsicher sind.

Bearbeiten: Wie die Jungs hier sagen, ist dies nicht immer der Fall, und dies gilt eindeutig für Klassen, die auf diese Weise in der BCL entworfen wurden, nicht für vom Benutzer erstellte Klassen, für die dies nicht gilt.


3
Puh! Schließlich habe ich die Bedeutung dieses Hinweises verstanden, der in der MSDN-Dokumentation so häufig vorkommt. Wenn MS eine statische Methode (in der dieser Hinweis veröffentlicht wird) in BCL entwirft, greift sie grundsätzlich nicht auf Variablen / Mitglieder / Zustände zu, die außerhalb des Geltungsbereichs dieser Methode liegen. Sie stützen sich vollständig auf lokale Variablen mit Methodenbereich, nur um die Logik dieser Methode zu implementieren. Sehr froh, dass Sie geteilt haben.
RBT

@Marcote, ist das Gegenteil nicht der Fall? Instanzmitglieder sind sicher, da es eine pro Instanz gibt. Statische Mitglieder sind jedoch nicht threadsicher, da sie von allen Instanzen dieser Klasse gemeinsam genutzt werden. quora.com/…
Fractal

1
es hängt davon ab, ob. Ich würde niemals ein Instanzmitglied standardmäßig sicher behandeln. Deshalb eine ganze Reihe von Bibliotheken und unter anderem um Datenkorruption zu vermeiden.
Marcote

1
Okay, danke @Marcote. Ich finde langsam heraus, dass ich viel lernen muss.
Fraktal
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.