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);
}
}