2012-03-24 2 views
114

Gibt es allgemeine Regeln/Richtlinien dafür, was eine Methode threadsicher macht? Ich verstehe, dass es wahrscheinlich eine Million einmaliger Situationen gibt, aber wie sieht es überhaupt aus? Ist es so einfach?Was macht eine Methode fadensicher? Wie lauten die Regeln?

  1. Wenn eine Methode nur auf lokale Variablen zugreift, ist sie Thread-sicher.

Ist es das? Gilt das auch für statische Methoden?

Eine Antwort, die von @Cybis vorgesehen war:

Lokale Variablen unter Threads gemeinsam genutzt werden kann, da jeder Thread seinen eigenen Stapel bekommt.

Ist das auch bei statischen Methoden der Fall?

Wenn eine Methode ein Referenzobjekt übergeben wird, bricht die Thread-Sicherheit ab? Ich habe etwas recherchiert, und es gibt eine Menge da draußen über bestimmte Fälle, aber ich hatte gehofft, in der Lage zu sein, mit nur ein paar Regeln, Richtlinien zu definieren, um sicherzustellen, dass eine Methode threadsicher ist.

Also ich denke, meine ultimative Frage ist: "Gibt es eine kurze Liste von Regeln, die eine thread-sichere Methode definieren? Wenn ja, was sind sie?"

BEARBEITEN
Viele gute Punkte wurden hier gemacht. Ich denke, die wirkliche Antwort auf diese Frage lautet: "Es gibt keine einfachen Regeln, um die Thread-Sicherheit zu gewährleisten." Cool. Fein. Aber im Allgemeinen Ich denke, die angenommene Antwort bietet eine gute, kurze Zusammenfassung. Es gibt immer Ausnahmen. So sei es. Ich kann damit leben.

+44

Sie dürfen nicht auf Variablen zugreifen, auf die auch andere Threads ohne Locketh zugreifen. –

+3

Hanth Pathant hat sich in einen Igor verwandelt! –

+3

Auch .. 'Du darfst nicht auf Variablen zugreifen, die auch von anderen Threads ohne Locketh zugänglich sind' - es ist nicht so wichtig, wenn der gelesene Wert gelegentlich nicht der letzte ist oder tatsächlich grob inkorrekt ist. –

Antwort

99

Wenn eine Methode (instance oder statisch) nur innerhalb dieses Verfahren scoped Variablen verweist, dann ist es sicher, Gewinde, da jeder Faden einen eigenen Stapel hat:

In diesem Fall könnten mehrere Threads ThreadSafeMethod ohne Ausgabe gleichzeitig rufen.

public class Thing 
{ 
    public int ThreadSafeMethod(string parameter1) 
    { 
     int number; // each thread will have its own variable for number. 
     number = parameter1.Length; 
     return number; 
    } 
} 

Dies gilt auch, wenn die Methode Methode andere Klasse aufruft, die nur Referenzvariablen lokal scoped: Dann

public class Thing 
{ 
    public int ThreadSafeMethod(string parameter1) 
    { 
     int number; 
     number = this.GetLength(parameter1); 
     return number; 
    } 

    private int GetLength(string value) 
    { 
     int length = value.Length; 
     return length; 
    } 
} 

Wenn eine Methode eine beliebige (Objektzustand) Eigenschaften oder Felder (instance oder statisch) zugreift Sie müssen Sperren verwenden, um sicherzustellen, dass die Werte nicht von einem anderen Thread geändert werden.

public class Thing 
{ 
    private string someValue; // all threads will read and write to this same field value 

    public int NonThreadSafeMethod(string parameter1) 
    { 
     this.someValue = parameter1; 

     int number; 

     // Since access to someValue is not synchronised by the class, a separate thread 
     // could have changed its value between this thread setting its value at the start 
     // of the method and this line reading its value. 
     number = this.someValue.Length; 
     return number; 
    } 
} 

Sie sollten sich bewusst sein, dass alle in dem Verfahren übergebenen Parameter, die nicht entweder eine Struktur oder unveränderlich sind, könnten von einem anderen Thread außerhalb des Anwendungsbereichs des Verfahrens mutiert werden.

Um eine ordnungsgemäße Parallelität zu gewährleisten, müssen Sie Sperren verwenden.

für weitere Informationen siehe lock statement C# reference und ReadWriterLockSlim.

Schloss ist meist nützlich für den einen nach der anderen Funktionalität bereitstellt,
ReadWriterLockSlim nützlich, wenn Sie mehrere Leser und einzelne Autoren müssen.

+9

Im dritten Beispiel ist 'private string someValue;' nicht 'statisch', so dass jede Instanz eine separate Kopie dieser Variablen erhält. Kannst du mir bitte erklären, wie das nicht threadsicher ist? – Bharadwaj

+16

@Bharadwaj wenn es eine Instanz der Klasse 'Thing' gibt, auf die mehrere Threads zugreifen –

+0

Ich habe diese Situation nicht gedacht! Danke für die Antwort :) – Bharadwaj

9

Es gibt keine feste Regel.

Hier sind einige Regeln zu Code Thread-sicher in .NET zu machen und warum diese nicht gute Regeln:

  1. Funktion und alle Funktionen, die sie aufruft, muss rein (keine Nebenwirkungen) und lokale Variablen verwenden. Obwohl dies Ihren Code threadsicher macht, gibt es auch sehr wenig interessante Dinge, die Sie mit dieser Einschränkung in .NET tun können.
  2. Jede Funktion, die auf ein gemeinsames Objekt wirkt, muss lock auf eine gemeinsame Sache. Alle Sperren müssen in der gleichen Reihenfolge ausgeführt werden. Dies macht den Code Thread sicher, aber es wird unglaublich langsam, und Sie können nicht mehrere Threads verwenden.
  3. ...

Es gibt keine Regel, dass der Code Thread-sicher macht, kann das einzige, was Sie tun, ist sicher, dass Ihr Code funktionieren, egal wie oft wird es jeder Thread aktiv ausgeführt wird, kann an jedem Punkt unterbrochen werden, wobei sich jeder Thread in seinem eigenen Zustand/Ort befindet, und dies für jede Funktion (statisch oder anderweitig), die auf gewöhnliche Objekte zugreift.

+8

Schlösser müssen nicht langsam sein. Schlösser sind unglaublich schnell; Eine unangetastete Sperre liegt in der Größenordnung von zehn bis einhundert ** Nanosekunden **. Angeklagte Sperren sind natürlich beliebig langsam; Wenn Sie verlangsamt werden, weil Sie Sperren infrage stellen, dann * rearchitect das Programm, um die Konkurrenz zu entfernen *. –

+2

Ich schätze, ich habe es versäumt, # 2 klar genug zu machen. Ich habe versucht zu sagen, dass es eine Möglichkeit gibt, Threads sicher zu machen: Sperren Sie jeden Zugriff auf gewöhnliche Objekte. Und unter der Annahme, dass es mehrere Threads gibt, wird es zu Konflikten kommen, und Sperren werden das Ganze verlangsamen. Wenn man Schlösser hinzufügt, kann man Schlösser nicht einfach blind hinzufügen, sie müssen an sehr guten strategischen Orten platziert werden. – earlNameless

92

Wenn eine Methode nur auf lokale Variablen zugreift, ist sie Thread-sicher. Ist es das?

Absolut nicht. Sie können ein Programm mit nur einem einzigen lokalen Variablen von einem einzelnen Thread zugegriffen schreiben, die dennoch nicht THREAD ist:

https://stackoverflow.com/a/8883117/88656

Heißt das auch für statische Methoden anwenden?

Absolut nicht.

Eine Antwort, die von @Cybis zur Verfügung gestellt wurde, war: "Lokale Variablen können nicht unter Threads geteilt werden, da jeder Thread seinen eigenen Stack bekommt."

Absolut nicht. Das Unterscheidungsmerkmal einer lokalen Variablen ist, dass es nur innerhalb des lokalen Bereichs sichtbar ist, nicht dass es auf dem temporären Pool zugewiesen ist. Es ist vollkommen legal und möglich, von zwei verschiedenen Threads auf dieselbe lokale Variable zuzugreifen. Sie können dies tun, indem Sie anonyme Methoden, Lambdas, Iteratorblöcke oder asynchrone Methoden verwenden.

Ist das auch bei statischen Methoden der Fall?

Absolut nicht.

Wenn eine Methode ein Referenzobjekt übergeben wird, bricht das die Threadsicherheit?

Vielleicht.

Ich habe etwas recherchiert, und es gibt eine Menge da draußen über bestimmte Fälle, aber ich hoffte, in der Lage zu sein, mit nur ein paar Regeln, Richtlinien zu folgen, um sicherzustellen, dass eine Methode ist fadensicher.

Sie müssen lernen, mit Enttäuschung zu leben. Das ist ein sehr schwieriges Thema.

Also, ich denke meine letzte Frage ist:?. „Gibt es eine kurze Liste von Regeln, die eine Thread-sichere Methode definieren

Nope Wie Sie meinem Beispiel früher sah eine leere Methode Sie können auch fragen "Gibt es eine kurze Liste von Regeln, die eine Methode sicherstellt richtig ist." Nein, gibt es nicht. Thread Sicherheit ist nichts anderes als eine extrem komplizierte Art der Korrektheit .

Darüber hinaus ist die Tatsache, dass Sie stellen die Frage, zeigt Ihr grundsätzliches Missverständnis über die Fadensicherheit. Gewindesicherheit ist eine globale, keine lokale Eigenschaft eines Programms. Der Grund, warum es so schwer ist, richtig zu kommen, ist, weil Sie vollständige Kenntnisse über das Threading-Verhalten des gesamten Programms haben müssen, um seine Sicherheit zu gewährleisten.

Betrachten Sie wieder mein Beispiel: jede Methode ist trivial. Es ist die Art und Weise, wie die Methoden auf einer "globalen" Ebene interagieren, die das Programm zum Deadlock macht. Sie können nicht jede Methode betrachten und es als "sicher" abchecken und dann erwarten, dass das ganze Programm sicher ist, mehr als Sie daraus schließen können, dass, weil Ihr Haus aus 100% nicht-hohlen Ziegeln besteht, das Haus auch ist nicht hohl. Die Hohlheit eines Hauses ist eine globale Eigenschaft der ganzen Sache, nicht ein Aggregat der Eigenschaften seiner Teile.

+0

Sie sagten: "Sie Ich kann nicht jede Methode betrachten und sie als "sicher" abtesten und dann erwarten, dass das ganze Programm sicher ist. " Einverstanden. Aber das frage ich eigentlich nicht. Ich hoffe zumindest zu verstehen, dass diese Methode die Dinge richtig macht, was die Thread-Sicherheit angeht. Sicher, einige * andere * Methoden können die Threads unsicher machen, aber zumindest sieht Methode A aus dieser Perspektive gut aus. –

+0

Übrigens schätze ich Ihre Antwort. Ich werde es später studieren, wenn ich Zeit habe. –

+7

Kernaussage: _Thread Sicherheit ist eine globale, keine lokale Eigenschaft eines Programms. _ –

Verwandte Themen