2013-05-29 3 views
20

Ist Thread sicher? Es scheint, dass die Task-Klasse threadsicher ist, also denke ich, dass es auch Thread-sicher ist, aber ich habe nirgends eine Bestätigung gefunden. Auch Thread-Sicherheit ist eine Voraussetzung für benutzerdefinierte Warter - ich meine für die IsCompleted, GetAwaiter, etc. Methoden? I.e. Wenn diese Methoden nicht threadsicher sind, wird es threadsicher sein? Ich erwarte jedoch nicht, dass ich bald einen benutzerdefinierten Warter brauche.Ist es in Ordnung, die gleiche Aufgabe von mehreren Threads zu erwarten - ist Thread sicher?

Ein Beispiel für Benutzerszenario: Lassen Sie uns sagen, dass ich eine Hintergrundaufgabe haben, die asynchron ein Ergebnis zurückgibt, die dann von mehreren Threads verwendet wird:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 

namespace scratch1 
{ 
    class Foo 
    { 
     Task<int> _task; 

     public Foo() 
     { 
      _task = Task.Run(async() => { await Task.Delay(5000); return 5; }); 
     } 

     // Called from multiple threads 
     public async Task<int> Bar(int i) 
     { 
      return (await _task) + i; 
     } 
    } 

    class Program 
    { 
     public static void Main(string[] args) 
     { 
      Foo foo = new Foo(); 

      List<Task> tasks = new List<Task>(); 
      foreach (var i in Enumerable.Range(0, 100)) 
      { 
       tasks.Add(Task.Run(async() => { Console.WriteLine(await foo.Bar(i)); })); 
      } 

      Task.WaitAll(tasks.ToArray()); 
     } 
    } 
} 

Antwort

14

Wie Sie erwähnt, ist await dünn genug, dass es doesn sehe Threads überhaupt nicht.

Der mit await verbundene Code (der vom Compiler generierte Code innerhalb der Statusmaschine und die Unterstützungsklassen in der BCL) wird immer nur mit einem Thread gleichzeitig ausgeführt. (er kann zu einem anderen Thread wechseln, wenn er von dem erwarteten zurückkommt, aber der vorherige Lauf ist bereits beendet)

Die tatsächliche Thread-Sicherheit hängt von dem Objekt ab, auf das Sie warten.
Es muss eine thread-sichere Möglichkeit geben, Callbacks hinzuzufügen (oder await es zweimal auf einmal brechen kann).

Darüber hinaus muss es den Rückruf genau einmal aufrufen, oder es kann die Zustandsmaschine brechen. (vor allem, wenn es seinen Callback auf zwei Threads zur gleichen Zeit läuft, werden die Dinge schrecklich schief gehen)

Task ist thread-safe.

+5

Ihre erste Aussage kann Leute in die Irre führen, dass "erwarten" grundsätzlich unsicher ist ... wohingegen ich denke, dass Sie weder von Natur aus sicher noch unsicher sind - es delegiert nur an das, was erwartet, und wenn das 'Aufgabe' ist, in Ordnung. –

+0

@JonSkeet: Guter Punkt. Ist das besser? – SLaks

+0

Definitiv, danke. Obwohl "wird immer nur auf einem Thread laufen" sollte wahrscheinlich "wird immer nur auf einen Thread zu einem Zeitpunkt pro Methode aufrufen (was einer einzigen Instanz der State Machine entspricht)". Es kann durchaus zwischen Threads an 'have' Punkten hin- und herspringen, aber es wird nicht gleichzeitig auf mehreren Threads laufen. (Zumindest nicht, wenn du es fürchterlich missbrauchst ... was immer Spaß macht.) –

Verwandte Themen