Kri*_*erg 9 .net c# task-parallel-library async-await
我正在编写一个库,其中包括基于.Net Tasks的调度功能(不是标准TaskScheduler,IScheduler...).我正在使用TaskCompletionSource,并且Task.Status对于表示底层操作的状态至关重要,包括 TaskStatus.Created即已创建但尚未启动.我知道返回的任务通常应该很热,但对于我手动控制的代理任务,我确实最初想要它们Created.
不幸的是,我的初始状态TaskCompletionSource.Task是WaitingForActivation,即它已经过去了Created.换句话说,TaskCompletionSource支持两种状态,但我需要三种状态:
问题:如何获得Task可手动设置为三种不同状态的信息?即Task.Status可以设置为:
1)Created
2)WaitingForActivation/ WaitingForChildrenToComplete/ WaitingToRun/ Running
3)其中一个RanToCompletion/ Canceled/Faulted
下面的代码可以理解为抱怨类型不匹配.我可以通过改变new Task<TResult>来包装任务new Task<Task<TResult>>,但是要回到Task<TResult>我Unwrap()必须的状态WaitingForActivation,并且解开的任务将具有状态,让我回到原点.
我将有大量的这些,所以阻止一个线程与Wait()每个不是一个选项.
我已经考虑过继承Task和覆盖成员(使用new),但是如果可能的话,给库用户一个实际的Task而不是一个很好DerivedTask,特别是因为我在许多其他地方也提出了常规的任务.
想法?
private TaskCompletionSource<TResult> tcs;
private async Task<TResult> CreateStartCompleteAsync()
{
await tcs.Task;
if (tcs.Task.IsCanceled)
{
throw new OperationCanceledException("");
}
else if // etc.
}
public ColdTaskCompletionSource()
{
tcs = new TaskCompletionSource<TResult>();
Task = new Task<TResult>(() => CreateStartCompleteAsync());
}
Run Code Online (Sandbox Code Playgroud)
错误:
*无法将lambda表达式转换为委托类型'System.Func',因为块中的某些返回类型不能隐式转换为委托返回类型
*无法将类型'System.Threading.Tasks.Task'隐式转换为'TResult "
虽然我同意@ usr在评论中的观点,但从技术上讲,您仍然可以拥有提供以下状态的实现:
Created WaitingToRunRanToCompletion/Canceled/Faulted为了避免阻塞线程与Task.Wait,你可以使用一个内部帮手TaskScheduler,它会首先要从其过渡的任务Created来WaitingToRun,最终,已完成的国家之一.
下面的代码说明了这个概念.它只是经过了非常轻微的测试,可能不是完全线程安全的,也许可以改进以共享FakeTaskScheduler跨多个任务的单个实例.
public class ColdTaskCompletionSource
{
public sealed class FakeTaskScheduler : TaskScheduler
{
Task _task;
public FakeTaskScheduler()
{
}
protected override void QueueTask(Task task)
{
_task = task;
}
protected sealed override bool TryDequeue(Task task)
{
if (task != _task)
return false;
_task = null;
return true;
}
protected override IEnumerable<Task> GetScheduledTasks()
{
if (_task == null)
yield break;
yield return _task;
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return false;
}
public override int MaximumConcurrencyLevel
{
get { return 1; }
}
public bool Execute()
{
if (_task == null)
return false;
var task = _task;
_task = null;
return base.TryExecuteTask(task);
}
}
readonly Task _task;
readonly CancellationTokenSource _cts;
readonly object _lock = new Object();
readonly FakeTaskScheduler _ts = new FakeTaskScheduler();
Action _completionAction = null;
// helpers
void InvokeCompletionAction()
{
if (_completionAction != null)
_completionAction();
}
void Complete()
{
if (_task.Status != TaskStatus.WaitingToRun)
throw new InvalidOperationException("Invalid Task state");
_ts.Execute();
}
// public API
public ColdTaskCompletionSource()
{
_cts = new CancellationTokenSource();
_task = new Task(InvokeCompletionAction, _cts.Token);
}
public Task Task { get { return _task; } }
public void Start()
{
_task.Start(_ts);
}
public void SetCompleted()
{
lock (_lock)
Complete();
}
public void SetException(Exception ex)
{
lock (_lock)
{
_completionAction = () => { throw ex; };
Complete();
}
}
public void SetCancelled()
{
lock (_lock)
{
_completionAction = () =>
{
_cts.Cancel();
_cts.Token.ThrowIfCancellationRequested();
};
Complete();
}
}
}
Run Code Online (Sandbox Code Playgroud)