我的代码在单个线程中使用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升级的错误吗? 如果我不能,有没有关于这方面的官方文件?
好的,答案是:
operation_aborted
错误。 如果定时器在调用cancel()时已经过期,那么异步等待操作的处理程序将会:
基本上,我错误的假设,如果我使用单线程的io_service,那么每个操作将被阻止,而一些处理程序执行。
我报道的行为实际上很有意义,似乎每个使用Asio的人都知道这一点。 我已经梳理了Asio的邮件列表,并在 这里 , 这里和这里找到了很多关于这个主题的讨论。
例如,写入操作可能会在处理程序中成功完成,但是在调用套接字取消之前,将其完成处理程序发布到队列中。 据我所知,错误代码是由完成的操作的状态决定的,而不是处理程序从队列中取出并执行时的套接字状态。
考虑同时建立两个连接。 这两个处理程序将触发,一个将被处理第一个,第二个在队列中(或在不同的线程上处理)。 人们可以想到更多这样的例子。
所以为了实现你的需求,你需要更多的逻辑。