InvalidOperationException
在我正在实现的自定义上运行任务时,我偶尔会遇到以下TaskScheduler
情况。
调查此问题后,它似乎是 Mono 实现中的一个错误。当一个延续任务被标记时TaskContinuationOptions.ExecuteSynchronously
,它会被传递给任务调度器的TryExecuteTaskInline
方法;但是,如果后者拒绝执行它并返回false
,那么将不可避免地遇到以下异常(根据下面的代码摘录)。
有人可以建议一种在 Mono 上解决此问题的方法吗?我正在考虑改变我的TryExecuteTaskInline
实现,使其始终接受执行同步延续;但是,我还没有找到一种方法来确定一项任务是否是一个延续(不使用反射)。
System.InvalidOperationException: Start may not be called on a continuation task
at System.Threading.Tasks.Task.Start (System.Threading.Tasks.TaskScheduler scheduler) [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.RunSynchronouslyCore (System.Threading.Tasks.TaskScheduler scheduler) [0x00000] in <filename unknown>:0
at System.Threading.Tasks.TaskContinuation.Execute () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.ProcessCompleteDelegates () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.Finish () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.ThreadStart () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.Execute () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.TaskScheduler.TryExecuteTask (System.Threading.Tasks.Task task) [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Schedulers.WorkStealingTaskScheduler.DispatchLoop (CancellationToken cancellationToken) [0x00000] in <filename unknown>:0
我粘贴在相关(精简)部分下方......
class TaskContinuation
{
public void Execute ()
{
// ...
if ((continuationOptions & TaskContinuationOptions.ExecuteSynchronously) != 0)
task.RunSynchronouslyCore (task.scheduler);
else
task.Schedule ();
}
}
…来自Task.cs
:
public class Task
{
internal void RunSynchronouslyCore(TaskScheduler scheduler)
{
// ...
if (scheduler.RunInline(this, false))
return;
Start(scheduler);
Wait();
}
public void Start(TaskScheduler scheduler)
{
// ...
if (IsContinuation)
throw new InvalidOperationException("Start may not be called on a continuation task");
SetupScheduler(scheduler);
Schedule();
}
}
……从TaskScheduler.cs
:
public abstract class TaskScheduler
{
protected abstract bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued);
internal bool RunInline(Task task, bool taskWasPreviouslyQueued)
{
// ...
return TryExecuteTaskInline(task, taskWasPreviouslyQueued);
}
}