如何制作非阻塞等待句柄?

时间:2015-12-31 15:59:32

标签: c# wpf autoresetevent waithandle

基本上,我正在做的是创建一个Web服务器来处理API调用,然后当它完成时继续执行方法,基本上是这样的:

new WebServer(myAutoResetEvent);
myAutoResetEvent.WaitOne();

然而,这阻止了线程直到那时。有没有办法让这个异步?将它包裹在await Task.Run()电话中是否正常,即await Task.Run(() => myAutoResetEvent.WaitOne())

谢谢!

3 个答案:

答案 0 :(得分:3)

通常情况下,WebServer ctor不应该做任何有趣的事情。应该有一个运行服务器的Task WebServer.RunAsync函数。然后,您可以使用生成的任务进行同步和协调。

如果您不想要,可以使用TaskCompletionSource<object>作为一次性异步就绪事件。

我相信ThreadPool课程有效地等待WaitHandle设置,但这是一个更糟糕的解决方案。

答案 1 :(得分:2)

你不应该阻塞ThreadPool个线程,这是导致ThreadPool饥饿的快速方法,而是提供异步等待WaitHandle个实例的方法,这称为{ {1}}。

通过使用ThreadPool.RegisterWaitForSingleObject,当ThreadPool.RegisterWaitForSingleObject可用时,将调用回调,不幸的是,这不是async / await兼容的开箱即用,这是一个完整的实现,使得async / await兼容如下:

WaitHandle

唯一的限制是,这不能与public static class WaitHandleExtensions { public static Task WaitOneAsync(this WaitHandle waitHandle, CancellationToken cancellationToken) { return WaitOneAsync(waitHandle, Timeout.Infinite, cancellationToken); } public static async Task<bool> WaitOneAsync(this WaitHandle waitHandle, int timeout, CancellationToken cancellationToken) { // A Mutex can't use RegisterWaitForSingleObject as a Mutex requires the wait and release to be on the same thread // but RegisterWaitForSingleObject acquires the Mutex on a ThreadPool thread. if (waitHandle is Mutex) throw new ArgumentException(StringResources.MutexMayNotBeUsedWithWaitOneAsyncAsThreadIdentityIsEnforced, nameof(waitHandle)); cancellationToken.ThrowIfCancellationRequested(); var tcs = new TaskCompletionSource<bool>(); var rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle, OnWaitOrTimerCallback, tcs, timeout, true); var cancellationCallback = BuildCancellationCallback(rwh, tcs); using (cancellationToken.Register(cancellationCallback)) { try { return await tcs.Task.ConfigureAwait(false); } finally { rwh.Unregister(null); } } } private static Action BuildCancellationCallback(RegisteredWaitHandle rwh, TaskCompletionSource<bool> tcs) { return () => { if (rwh.Unregister(null)) { tcs.SetCanceled(); } }; } private static void OnWaitOrTimerCallback(object state, bool timedOut) { var taskCompletionSource = (TaskCompletionSource<bool>)state; taskCompletionSource.SetResult(!timedOut); } } 一起使用。

这可以这样使用:

Mutex

答案 2 :(得分:0)

另一种需要考虑的方法是使用HttpSelfHostServer(System.Web.Http.SelfHost.dll)并将所有线程详细信息留给其实现。

var config = new HttpSelfHostConfiguration("http://localhost:9999");
var tcs = new TaskCompletionSource<Uri>();

using (var server = new HttpSelfHostServer(config, new MessageHandler(tcs)))
{
    await server.OpenAsync();

    await tcs.Task;

    await server.CloseAsync();
}

return tcs.Task.Result;

class MessageHandler : HttpMessageHandler
{
    private readonly TaskCompletionSource<Uri> _task;

    public MessageHandler(TaskCompletionSource<Uri> task)
    {
        _task = task;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        _task.SetResult(request.RequestUri);
        return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
    }
}