2014-12-23 19 views
13

Betrachten Sie den folgenden Code.Task.Run im statischen Initialisierer

static class X 
{ 
    public static int Value = Task.Run(() => 0).Result; 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var value = X.Value; 
    } 
} 

Task.Run aufrufen und dann Result im statischen Initialisierer bewirkt, dass das Programm dauerhaft einzufrieren. Warum?

Antwort

14

Sie sehen Deadlock bei der Klasseninitialisierungssperre der CLR.

Grundsätzlich kann nichts in der Klasse X verwendet werden, bis die Klasse initialisiert ist. Aber Ihre anonyme Methode () => 0 ist zu einem Mitglied der Klasse kompiliert. Die Klasseninitialisierung wird nicht abgeschlossen, bis die Task abgeschlossen werden kann, aber die Task kann nicht abgeschlossen werden, da es von einer Methode abhängt, die nicht ausgeführt werden darf, bis die Initialisierung der Klasse abgeschlossen ist.

Deadlock.

Ihr Beispiel ist eindeutig erfunden, daher ist es unmöglich, Ratschläge zu geben, wie Sie Ihr tatsächliches Problem lösen können. In diesem speziellen Beispiel könnten Sie die Initialisierung durch Task.FromResult(0).Result; ersetzen, aber das ist natürlich noch komplizierter; Wenn das tatsächlich möglich wäre, würden Sie einfach 0 dem Feld zuweisen.

Aber was auch immer Ihr Real-World-Szenario ist, besteht die Möglichkeit, es zu beheben, keine Situation zu schaffen, in der die Initialisierung der Klasse von einer externen Komponente abhängt, die diese Klasse benötigt. Sie können zum Beispiel den Wert Lazy<T> verwenden, um den Wert zu initialisieren, oder einfach die Methode direkt aufrufen (was zulässig wäre).

Ob ein Beispiel erfunden ist oder nicht, es gibt nie einen Punkt beim Starten einer Task, nur um den aktuellen Thread sofort zu blockieren, bis es abgeschlossen ist. Wenn Sie also einen Code haben, der zwar nicht genau wie dieses Beispiel funktioniert, aber immer noch dasselbe tut, liegt es nahe, ihn so zu ändern, dass er seriell und single-thread ausgeführt wird.

+0

Es ist das interne Arbeiten der statischen Klasseninitialisierung und der Klasseninitialisierungssperre, mit denen ich nicht vertraut war. Das tatsächliche Szenario, dem ich begegnete, war Code, der viel komplizierter war, aber ich konnte es auf dieses kleine Beispiel reduzieren. Kein Problem mit einer besseren Lösung oder Workaround. Danke für die Erklärung! –

0

Ich denke, die Erklärung des Problems ist nicht korrekt.

Grundsätzlich kann nichts in der Klasse X verwendet werden, bis die Klasse initialisiert ist.


aber die Aufgabe kann nicht abgeschlossen werden, weil es an einer Methode abhängt, bis die Initialisierung der Klasse komplett laufen nicht erlaubt ist.

wenn ja, in diesem Fall sollten Sie einen Compiler-Fehler erhalten, aber nicht auf Laufzeit Deadlock.

Auf jeden Fall ist dieser Code legal

static class X 
{ 
    public static int Value = Method(); 
    private static int Method() 
    { 
     return 0; 
    } 
} 

Here Erklärung des Problems ist.

Verwandte Themen