wpf 顶级任务导致错误“当前 SynchronizationContext 不能用作 TaskScheduler。”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21370904/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Top Level Task Causes Error "The current SynchronizationContext may not be used as a TaskScheduler."
提问by Buck
I do not see the answer yet, although I have looked on stackoverflow and documentation.
我还没有看到答案,尽管我已经查看了 stackoverflow 和文档。
This error is coming up over the ContinueWidth below if I call the code that creates the tasks from a timer handler or within another task. For example, if it is wrapped in another task that creates tasks every interval (e.g. every 1 second) as follows. The only reason why I have the high level task is to create these lower tasks every interval.
如果我调用从计时器处理程序或另一个任务中创建任务的代码,则会在下面的 ContinueWidth 上出现此错误。例如,如果它被包装在另一个任务中,该任务每间隔(例如每 1 秒)创建一个任务,如下所示。我有高级任务的唯一原因是每个时间间隔创建这些低级任务。
//Higher level task creation
//创建更高级别的任务
...
...
Task task = Task.Factory.StartNew(new Action(UpdateAllDuringInterval));
...
...
private void UpdateAllDuringInterval()
{
Stopwatch stopWatch = new Stopwatch();
do
{
// Start the stopwatch
stopWatch.Start();
// Create tasks
List<Task> tasks = CreateTasksAndStart();
// Wait for the tasks to complete if testing, since want to check results
if (this._testMode)
{
Task[] taskArray = tasks.ToArray();
Task.WaitAll(taskArray);
}
if (!_testMode)
{
// Get remaining time to complete interval and sleep for that time
int remainingTimeInMilliseconds = this._pollingIntervalInMilliseconds -
(int) stopWatch.Elapsed.TotalMilliseconds;
// truncating milliseconds
if (remainingTimeInMilliseconds > 0)
Thread.Sleep(remainingTimeInMilliseconds);
// will give time to CPU. Note that using Sleep used to be frowned upon but no longer due to advantages in multitasksing/CPU utilization
}
} while (!_testMode); // continue updating stocks once per interval if not testing
}
private List<Task> CreateTasksAndStart()
{
var tasks = new List<Task>();
lock (syncLock)
{
for (int i = 0; i < _stocksToUpdate.Count; i++)
{
var item = _stocksToUpdate[i];
var initialTask = Task.Factory.StartNew(() =>
{
GetUpdatedStockInformation(item);
});
var continuationTask = initialTask.ContinueWith((antecendent) =>
{
UpdateUIWithUpdatedStockInformation();
}
, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
// For testing, we want to wait on the continuation task to make sure updates are done
tasks.Add(continuationTask);
}
}
return tasks;
}
If more information is needed, just let me know. Feel free to give me other pitfalls of this code as well. Thanks!
如果需要更多信息,请告诉我。随意给我这个代码的其他陷阱。谢谢!
回答by Mike Zboray
The cause is simple however the solution may require you to redesign some of the interactions of your tasks. You do not have a SynchronizationContextset (i.e. SynchronizationContext.Currentis null), and therefore a TaskSchedulercannot be created from the it. One option is to call TaskScheduler.FromCurrentSynchronizationContext()in a place where you are running on the UI thread and then pass in down to the method where the continuations are constructed. Another is create the tasks an pass them up so that the UI thread can attach the continuations.
原因很简单,但解决方案可能需要您重新设计任务的某些交互。你没有一个SynchronizationContext集合(即为SynchronizationContext.Current空),因此TaskScheduler不能从它创建一个。一种选择是TaskScheduler.FromCurrentSynchronizationContext()在您在 UI 线程上运行的地方调用,然后向下传递到构造延续的方法。另一个是创建任务并传递它们,以便 UI 线程可以附加延续。
It is generally considered a code smell to have flags like _testModethat, presumably, only test code sets. Then you've got some interaction which you are not really testing because the test code does one thing, but the actual application does another.
通常认为有这样的标志是一种代码异味_testMode,大概只有测试代码集。然后你有一些你没有真正测试的交互,因为测试代码做一件事,但实际的应用程序做另一件事。

