7

ich manuell eine Aufgabe konstruieren:Task.Start, Task.RunSynchronously und Synchronisationskontext

var task = new Task(() => 
    Debug.WriteLine("Task")); 

es dann manuell starten:

task.Start(TaskScheduler.FromCurrentSynchronizationContext()); 

Ich erwarte, dass es über SynchronizationContext.Post geplant werden, sein.

Aber wenn es auf diese Weise beginnen:

task.RunSynchronously(TaskScheduler.FromCurrentSynchronizationContext()); 

Wird es über SynchronizationContext.Send oder direkt ausgeführt werden von der Lambda-Aufgabe aufrufen?

Antwort

8

Wird es über SynchronizationContext.Send oder direkt über ausgeführt, wobei das Lambda der Task aufgerufen wird?

Hier ist was los ist. Zuerst versucht Task.RunSynchronously die Aufgabe auszuführen, indem scheduler.TryExecuteTaskInline Aufruf. Im Fall mit SynchronizationContextTaskScheduler, es ist dies:

protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) 
{ 
    return ((SynchronizationContext.Current == this.m_synchronizationContext) && base.TryExecuteTask(task)); 
} 

Also, wenn auf dem gleichen Synchronisations Zusammenhang wird die Aufgabe Lambda direkt in base.TryExecuteTask ausgeführt werden.

Andernfalls stellt die Task den Taskplaner mit Task.RunSynchronously in den Wartezustand und blockiert die Task WaitHandle mit der blockierenden Warte.

SynchronizationContext.Send tut nicht in jedem Fall beteiligt werden.

Was ist das interessant ist. AFAIK, in WPF kann es auf dem Haupt UI Thread mehr DispatcherSynchronizationContext Kontexte sein, ein pro Fenster der obersten Ebene. Daher kann RunSynchronously theoretisch zu einem Deadlock führen. Ich werde das überprüfen.

Aktualisiert, der Deadlock in WPF ist real. Hier ist, wie man Repro:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     this.Loaded += MainWindow_Loaded; 
    } 

    void MainWindow_Loaded(object sMainWindow, RoutedEventArgs eMainWindow) 
    { 
     var task = new Task(() => 
      Debug.WriteLine("Task")); 

     var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

     var window1 = new Window(); 
     window1.Loaded += (sWindow1, eWindow1) => 
     { 
      // Deadlock in WPF 
      task.RunSynchronously(scheduler); 
      Debug.WriteLine("Done!"); 
     }; 
     window1.Show(); 
    } 
} 
+0

Ich bin eine harte Zeit, um den Stillstand Vorstellungsvermögen, hier. Stört es Sie zu beschreiben, wie dies zu einem Deadlock führt? d. h. wer konkurriert um die Ressource? – Thomas

+1

@Thomas, gibt es kein Rennen, aber die Aufgabe Abschluss Rückruf wird über SynchrnizationContext.Post geschrieben, und dann die Gewindeblöcke auf den Griff der gleichen Aufgabe innerhalb task.RunSynchronously, in eine Sackgasse führt. Ich werde dies aus dem Telefon, nicht mehr ins Detail gehen, aber man konnte die Suche nach Stephen ist eindeutig „nicht auf asynchronen Code sperren“. – Noseratio