我在asio :: ip :: tcp :: socket上有一系列嵌套异步操作,我想有可能从其他线程尽快停止它。 这是一些伪:
socket->async_something(buffer, CallbackLambdaHeader
{
if (errorcode)
{
//exit the sequence
}
// some code
socket->async_something(buffer, CallbackLambdaHeader
{
if (errorcode)
{
//exit the sequence
}
// some code
socket->async_something(buffer, CallbackLambdaHeader
{
if (errorcode)
{
//exit the sequence
}
// etc
});
});
});
问题是简单的socket->cancel()
调用不会一直有效,因为在调用的那一刻,其中一个回调可能正在运行。因此,不会有取消排队的操作,但正在运行的回调可以很快添加一个并继续序列。
我希望socket->cancel()
之后的异步操作也被取消(立即完成operation_aborted
错误)。
唯一的想法是以某种方式将每个呼叫包裹在mutex.lock()
中并使用取消标记
//thread1:
mutex.lock();
cancel = true;
socket->cancel();
mutex.unlock();
//thread 2:
mutex.lock();
if (!cancel)
{
socket->async_something(buffer, CallbackLambdaHeader
{
if (errorcode)
{
//exit the sequence
}
// some code
mutex.lock();
if (!cancel)
{
socket->async_something(buffer, CallbackLambdaHeader
{
if (errorcode)
{
//exit the sequence
}
// some code
mutex.lock();
if (!cancel)
{
socket->async_something(buffer, CallbackLambdaHeader
{
if (errorcode)
{
//exit the sequence
}
// etc
});
}
else
{
//exit the sequence
}
mutex.unlock();
});
}
else
{
//exit the sequence
}
mutex.unlock();
});
}
else
{
//exit the sequence
}
mutex.unlock();
但它看起来很糟糕。
听说过io_service::strand
,但不知道如何在这里使用它。使用.post()和socket->cancel()
方法?有没有保证情况{回调,取消,回调}是不可能的?
答案 0 :(得分:0)
{callback,cancel,callback}总是可行的,这不是你想要避免的。事实上,任何取消将始终导致任何待处理操作完成,因此至少会有一个回调(带有错误代码表明操作已中止)。
一旦您知道套接字已被“取消”(取消操作不会这样做:它取消操作,您希望/需要避免的是安排新任务 >,而不是套接字)。
我看到两件事情,视情况而定,可能是你想要的:
如果要关闭套接字及其上的所有操作,请永久
我只是发布一个任务来关闭套接字(当然也会取消挂起的操作)。好处是你可以在意外地为该套接字安排新操作之前检查套接字状态[sock.is_open
] http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/basic_stream_socket/is_open.html)。
_service.post([this] { sock.close(); });
如果您有多个线程
sock
- ning服务,您需要一个链来避免数据争用访问run
变量。见Why do I need strand per connection when using boost::asio?
如果要取消特定操作链而使套接字保持打开¹,则每个套接字都可以有一个标志,指示操作何时被取消。
所涉及的所有完成处理程序已经收到包含error_code
的{{1}},因此应该很容易避免在该链中进行“跟进”工作。
在回调lambda标题中输入这样的内容:
boost::asio::error::operation_aborted
事实上,您可能希望在大多数错误上执行此操作。
if (ec == boost::asio::error::operation_aborted)
return;
如果某些其他线程即将发布新的独立异步操作(链)并且您想要阻止它(仅在没有关闭的情况下),该标志仅仅是有利的套接字,否则使用解决方案#1)。
该套接字不需要同步,因为您不与尚未共享 if (ec)
return; // log `ec.message()`?
的任何人共享该套接字。 <{1}}也不是线程安全的,因此您知道访问该标志必须是安全的。
同样,如果那不是真的,你需要一条链开始。
&GT;
拥有一个服务线程意味着你有一个隐含的链,你可以避免复杂性,即使你可能有许多线程通过永远不直接发布异步操作来发布任务:
sock
这样可以确保所有套接字操作都在隐式链上。
¹我实际上想不出一个有意义的协议,但也许是数据报协议(?)