我有单个外部资源 - 命名管道。我需要能够执行以下操作:
我不太想出一种优雅的方法来做到这一点(想到一件事 - 带超时的读/写锁)。
对于此类问题有纯异步解决方案吗?
您似乎可以使用队列来实现此目的,就像戴夫在评论中建议的那样。
TaskCompletionSource<TResult>
的帮助下,您可以创建自己的任务,您可以用我们自己的逻辑来完成这些任务。
以下是一个简单的不完整示例(未经测试),说明如何实现类似的功能:
public class PipeAccess
{
private readonly ConcurrentQueue<ScheduledTask> _queue
public Task<string> GetResult(string input) {
var schedule = new ScheduledTask(input);
_queue.Enqueue(schedule);
return schedule.Completion.Task;
}
private sealed class ScheduledTask
{
private CancellationTokenSource _timeout;
private IDisposable _timeoutRegistration;
public ScheduleTask(string input)
{
Input = input;
Completion = new TaskComletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
_timeout = new CancellationTokenSource(TimeSpan.FromSeconds(30));
_timeoutRegistration = _timeout.Token.Register(() => Completion.TrySetCancelled());
}
public string Input { get; }
public TaskCompletionSource<string> Completion { get; }
public bool StartProcessing()
{
_timeoutRegistration.Dispose();
_timeout.Dispose();
return !Completion.Task.IsCancelled;
}
}
}
在此示例中,我没有包含如何从队列中读取下一个任务的代码,但您首先调用
StartProcessing()
,以便停止超时。如果返回 false
,则该任务已超时,您可以转到队列中的下一项。否则你用管道做你的事情,结果可以设置为Completion.TrySetResult()
,发生的任何错误都可以设置为Completion.TrySetException()
。
TaskCreationOptions.RunContinuationsAsynchronously
,因为否则等待 PipeAccess.GetResult()
的代码将在此线程上继续,使您的 PipeAccess
等到该代码完成后才能继续执行下一个排队任务(并增加超时的可能性)。