我选择了回归Task<T>
和Task
从我对象的方法由GUI提供易于consumation。 一些方法只需等待其他种类waithandles的互斥。 有没有一种方法来构造Task
从WaitHandle.Wait()
这样我就不必阻塞一个treadpool线程。
Answer 1:
有一种方法可以做到这一点:您可以通过订阅的WaitHandle ThreadPool.RegisterWaitForSingleObject方法,并通过其包装TaskCompletionSource类:
public static class WaitHandleEx
{
public static Task ToTask(this WaitHandle waitHandle)
{
var tcs = new TaskCompletionSource<object>();
// Registering callback to wait till WaitHandle changes its state
ThreadPool.RegisterWaitForSingleObject(
waitObject: waitHandle,
callBack:(o, timeout) => { tcs.SetResult(null); },
state: null,
timeout: TimeSpan.MaxValue,
executeOnlyOnce: true);
return tcs.Task;
}
}
用法:
WaitHandle wh = new AutoResetEvent(true);
var task = wh.ToTask();
task.Wait();
Answer 2:
正如在谢尔盖Teplyakov的接受的答案的评论@gordy指出, MSDN提出与注册的WaitHandle的退订的实现。
我稍微修改了它在这里支持回调的结果是:如果注册已超时,任务返回false。 如果已收到信号,任务返回true:
public static class ExtensionMethods
{
public static Task<bool> WaitOneAsync(this WaitHandle waitHandle, int timeoutMs)
{
if (waitHandle == null)
throw new ArgumentNullException(nameof(waitHandle));
var tcs = new TaskCompletionSource<bool>();
RegisteredWaitHandle registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(
waitHandle,
callBack: (state, timedOut) => { tcs.TrySetResult(!timedOut); },
state: null,
millisecondsTimeOutInterval: timeoutMs,
executeOnlyOnce: true);
return tcs.Task.ContinueWith((antecedent) =>
{
registeredWaitHandle.Unregister(waitObject: null);
try
{
return antecedent.Result;
}
catch
{
return false;
throw;
}
});
}
}
用法和原来一样的答案:
WaitHandle signal = new AutoResetEvent(initialState: false);
bool signaled = await signal.WaitOneAsync(1000);
if (signaled)
{
Console.WriteLine("Signal received");
}
else
{
Console.WriteLine("Waiting signal timed out");
}
文章来源: Construct Task from WaitHandle.Wait