[英].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.