繁体   English   中英

.NET取消异步I / O操作

[英].NET cancelling async I/O operations

在这种特殊情况下,我正在编写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 *调用或者会发生不好的事情。

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

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

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

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

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

这是一篇很好的文章,解释了常见的模式和任务

备注:

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

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

通常,您将使用Begin / End模式,如下所示:

  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();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM