boost :: asioasynchronous处理程序在取消后调用没有错误

我的代码在单个线程中使用boost :: asio和io_service来执行各种套接字操作。 所有操作都是asynchronous的,每个处理程序都依赖于boost::system::error_code (特别是boost::asio::error::operation_aborted )来确定boost::asio::error::operation_aborted的结果。

它一直工作得很好,直到我改变了逻辑,使几个并发连接,并select最快的一个。 也就是说,当第一个async_read_some处理程序触发时,我取消了其他套接字(shutdown,close – everything)并继续使用当前的套接字。 在95%的情况下,其他套接字的读处理程序会被调用operation_aborted错误。 但有时候,这些读处理程序被调用没有错误,告诉我他们已经成功地接收了N个字节。

但是socket :: cancel()的文档声明 :

这个函数导致所有未完成的asynchronous连接,发送和接收操作立即完成,并且取消操作的处理程序将传递boost::asio::error::operation_aborted错误。

所以,问题:我真的可以依赖生产代码中的operation_aborted错误吗? 如果可以的话,Asio是从1.46.1升级的错误吗? 如果我不能,有没有关于这方面的官方文件?

好的,答案是:

  1. 不,我不能仅依赖于operation_aborted错误。
  2. 当然,这在Asio中并不是一个bug,只是缺乏经验而已。
  3. 有一点官方文件 。 这是定时器,而不是套接字,但是相同的原则适用:

如果定时器在调用cancel()时已经过期,那么异步等待操作的处理程序将会:

  • 已经被调用; 要么
  • 已经排队等候在不久的将来。

基本上,我错误的假设,如果我使用单线程的io_service,那么每个操作将被阻止,而一些处理程序执行。

我报道的行为实际上很有意义,似乎每个使用Asio的人都知道这一点。 我已经梳理了Asio的邮件列表,并在 这里 , 这里和这里找到了很多关于这个主题的讨论。

例如,写入操作可能会在处理程序中成功完成,但是在调用套接字取消之前,将其完成处理程序发布到队列中。 据我所知,错误代码是由完成的操作的状态决定的,而不是处理程序从队列中取出并执行时的套接字状态。

考虑同时建立两个连接。 这两个处理程序将触发,一个将被处理第一个,第二个在队列中(或在不同的线程上处理)。 人们可以想到更多这样的例子。

所以为了实现你的需求,你需要更多的逻辑。