我手动构建一个任务:
var task = new Task(() =>
Debug.WriteLine("Task"));
然后手动启动:
task.Start(TaskScheduler.FromCurrentSynchronizationContext());
我希望通过SynchronizationContext.Post
安排好。
但如果以这种方式开始:
task.RunSynchronously(TaskScheduler.FromCurrentSynchronizationContext());
是通过SynchronizationContext.Send
执行,还是直接通过调用任务的lambda来执行?
答案 0 :(得分:9)
是通过SynchronizationContext.Send还是直接执行 调用任务的lambda?
这是发生了什么。首先,Task.RunSynchronously
尝试通过调用scheduler.TryExecuteTaskInline
来执行任务。对于SynchronizationContextTaskScheduler
,就是这样:
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return ((SynchronizationContext.Current == this.m_synchronizationContext) && base.TryExecuteTask(task));
}
因此,如果在同一个同步上下文中,任务lambda将直接在base.TryExecuteTask
内执行。
否则,Task.RunSynchronously
将任务与任务调度程序排队,并使用阻塞等待阻塞任务的WaitHandle
。
SynchronizationContext.Send
不在任何情况下都会参与其中。
这有趣的是什么。 AFAIK,在WPF中,主UI线程上可能有几个DispatcherSynchronizationContext
上下文,每个顶级窗口一个。因此,理论上,RunSynchronously
可能会导致死锁。我要验证这个。
已更新,WPF中的死锁是真实。以下是如何重现:
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();
}
}