问题
I do not see the answer yet, although I have looked on stackoverflow and documentation.
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.
//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!
回答1:
The cause is simple however the solution may require you to redesign some of the interactions of your tasks. You do not have a SynchronizationContext set (i.e. SynchronizationContext.Current is null), and therefore a TaskScheduler cannot 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.
It is generally considered a code smell to have flags like _testMode that, 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.
来源:https://stackoverflow.com/questions/21370904/top-level-task-causes-error-the-current-synchronizationcontext-may-not-be-used