等待任何异步方法和(事件或布尔)

时间:2016-01-17 12:42:25

标签: c# async-await manualresetevent

我有这段代码:

ManualResetEvent EventListenerStopped;
...
while (true)
{
    IAsyncResult iar = this.ListenerHttp.BeginGetContext(ProcessRequest, null);
    if (WaitHandle.WaitAny(new[] { this.EventListenerStopped, iar.AsyncWaitHandle }) == 0)
        return;
}

基本上它等待两个事件中的任何一个:

  • 如果收到请求,它会处理它并等待下一个请求。
  • 如果引发了EventListenerStopped,它将退出循环。

此代码已经在生产中运行了很长时间。

我想尝试将其转换为新的await / async机制,但似乎无法找到一种简单的方法。

我尝试使用布尔值,调用者可以转为false。它显然不起作用,因为它只在收到并处理新请求后才退出循环:

bool RunLoop;
...
while (this.RunLoop)
{
    HttpListenerContext listenerContext = await this.ListenerHttp.GetContextAsync();
    ProcessRequest(listenerContext);
}

我想知道是否甚至可以用async / await重写我简单的旧式循环。如果是的话,有人会愿意告诉我怎么做?

2 个答案:

答案 0 :(得分:0)

它并不特定于async-await,但您可能正在寻找CancellationToken(无论如何都会使用大量的async-await代码):

http://blogs.msdn.com/b/pfxteam/archive/2009/05/22/9635790.aspx

' BlockingOperation'示例代码与您尝试执行的操作类似:

void BlockingOperation(CancellationToken token) 
{ 
   ManualResetEvent mre = new ManualResetEvent(false); 
   //register a callback that will set the MRE 
   CancellationTokenRegistration registration = 
      token.Register(() => mre.Set()); 
   using (registration) 
   { 
      mre.WaitOne(); 
      if (token.IsCancellationRequested) //did cancellation wake us? 
          throw new OperationCanceledException(token); 
   } //dispose the registration, which performs the deregisteration. 
}

答案 1 :(得分:0)

首先,我必须指出旧代码不太正确。处理Begin/End pattern时,必须始终呼叫End,即使您希望(或确实)取消操作。 End通常用于处置资源。

如果您确实想要取消,CancellationToken可能是最佳方法:

while (true)
{
  // Throws an OperationCanceledException when cancellationToken is canceled.
  var request = await this.ListenerHttp.GetContextAsync(cancellationToken);
  ProcessRequest(request);
}

还有其他选择 - 可能执行类似Task.WhenAny的操作,甚至还有AsyncManualResetEvent的实现,因此可以逐行创建相当于旧代码,但IMO取消令牌方法会更清晰。

例如,使用AsyncManualResetEvent from my AsyncEx library

AsyncManualResetEvent eventListenerStopped;
while (true)
{
  var task = GetContextAndProcessRequestAsync();
  if (await Task.WhenAny(eventListenerStopped.WaitAsync(), task) != task)
    return;
}

async Task GetContextAndProcessRequestAsync()
{
  var request = await this.ListenerHttp.GetContextAsync();
  ProcessRequest(request);
}

但就个人而言,我会改为使用CancellationToken