.NET取消异步I / O操作

时间:2011-09-11 12:55:34

标签: c# .net asynchronous io

在这种特殊情况下,我正在编写TCP / IP服务器,而我正在使用TcpListener.BeginAcceptTcpClient()来接受传入连接。服务器逻辑在实现IDisposable接口的单个​​类中实现:当调用Dispose()时,我想取消BeginAcceptTcpClient()操作。

现在用更一般的术语来说:当使用.NET的异步I / O模型(Begin *和End *)时,如何取消操作?

我的想法是这样的:

private volatile bool canceledFlag = false;

this.listener.BeginAcceptTcpClient(asyncResult =>
{
    if(this.canceledFlag) return;

    // ...
}, null);

Dispose()会将标志设置为true,并且还会调用this.listener.Stop()。 但是我记得已经读过,每次开始*调用必须有一个匹配的结束*调用或者会发生不好的事情。

那我该怎么做呢?请注意,我正在寻找一个通用解决方案来取消使用Begin *和End *方法 - 我只是给了我具体的使用方案,以帮助您理解我的问题。

3 个答案:

答案 0 :(得分:7)

通用解决方案是在您调用其BeginXxxx()方法的任何对象上调用Close()或Dispose()。这将导致回调运行,当您调用EndXxxx()时,您将获得ObjectDisposedException。您应该将其视为“使用结束”信号,立即清理并退出回调。虽然不赞成使用流量控制的例外是不可避免的。

对于TcpListener,使用Server.Dispose(),比调用Stop()更有效。

答案 1 :(得分:1)

我建议的替代方法是不使用async-Begin-End模式,而是使用Tasks。

您可以使用其中一个TaskFactory.FromAsync重载从Begin / End方法创建任务并使用它。您可以使用此.ContinueWith重载来指定具有自己的CancellationToken的延续以停止它。恕我直言,建议尽可能使用任务,因为下一版本的C#将构建在任务上,并且它具有async / await支持。

这是一个很好的article,解释了常见的模式和任务

REMARK:

在我原来的回答中,我说你可以使用.Dispose来杀死任务但这可能会导致严重的问题,因为你只能在完成状态下处理任务。

答案 2 :(得分:1)

异步过程完成时会调用AsyncCallback。它允许异步线程重新加入原始,然后任何异常都可以冒泡(而不是在后台丢失)。它还允许您捕获任何返回值。

通常,您将使用开始/结束模式,如下所示:

  Action action = () = > DoSomething();
  action.BeginInvoke(action.EndInvoke, null);

 Action action = () = > DoSomething();
 action.BeginInvoke(OnComplete, null);

 private void OnComplete(IAsyncResult ar)
 {
     AsyncResult result = (AsyncResult)ar;
     var caller = (Action)result.AsyncDelegate;
     caller.EndInvoke();

     // do something else when completed
 }

由特定实现提供一种在完成之前取消异步进程的方法。通常这是通过CancelAsync实现来完成的,该实现在内部提前停止任务。如果是TcpListener,您只需拨打listener.Server.Dispose();

即可
 TcpListener listener = new TcpListener(port);
 IAsyncResult = listener.BeginAcceptTcpClient(listener.EndAcceptTcpClient, null);

 // on dispose
 listener.Server.Dispose();