我正在编写一个包含调度功能的库(不是标准的TaskScheduler,IScheduler.)基于.Net任务。我正在使用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继承和重写成员(使用新的),但如果可能的话,最好给库用户一个实际的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());
}错误:
*无法将lambda表达式转换为委托类型'System.Func‘,因为块中的某些返回类型不能隐式转换为委托返回类型
*无法隐式地将“System.Threading.Tasks.Task”转换为“TResult”
发布于 2015-02-04 15:26:18
虽然我同意@usr在评论中的观点,但从技术上讲,您仍然可以有一个提供以下状态的实现:
CreatedWaitingToRunRanToCompletion/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();
}
}
}发布于 2015-02-04 11:56:25
你不能以合理的方式。
Task状态是在内部处理的,手动创建任务的惟一API是使用TaskCompletionSource。您也不能从Task继承,因为Status属性只是一个getter,并且由于它是内部的,所以您无法到达备份字段m_stateFlags。
但是,不合理的方法是创建一个等待TaskCompletionSource的任务,并且控制任务的状态是控制TaskCompletionSource
var taskCompletionSource = new TaskCompletionSource<bool>();
var cancellationTokenSource = new CancellationTokenSource();
var task = new Task(() => taskCompletionSource.Task.Wait(cancellationTokenSource.Token), cancellationTokenSource.Token); // task.Status == TaskStatus.Created
task.Start(); // task.Status == TaskStatus.Running
taskCompletionSource.SetResult(false) // task.Status == TaskStatus.RanToCompletion或
taskCompletionSource.SetException(new Exception("")) // task.Status == TaskStatus.Faulted或
cancellationTokenSource.Cancel() // task.Status == TaskStatus.Cancelled我不是真的建议你这么做。我不知道您为什么要控制Task的状态,但是您可能需要创建自己的构造,您可以自己管理自己,而不是强迫Task进行它本来不适合的设计。
https://stackoverflow.com/questions/28319630
复制相似问题