当我尝试使用boost::asio::strand
wrap
函数时,似乎导致来自shared_ptr
的shared_from_this
变为NULL,所以当它第二次执行时,它会导致程序崩溃。
但是,这仅在绑定(bind)的函数采用 无参数 时才会发生。
设置观察点并检查调用堆栈后,此行为似乎是由 shared_ptr
交换值的移动构造函数引起的,该构造函数源自 async_result_init
和 BOOST_ASIO_MOVE_CAST
。
我的问题是,我应该如何正确使用 wrap
来避免这种情况发生?
下面是一个简单的示例,向您展示我的意思:
class object : public boost::enable_shared_from_this<object> {
public:
object()
: service(new boost::asio::io_service),
work(new boost::asio::io_service::work(*service)),
strand(*service),
value(0) {}
void workerThread() {
service->run();
}
void run() {
func_int = strand.wrap(boost::bind(&object::handler_int, shared_from_this(), _1));
func_void = strand.wrap(boost::bind(&object::handler_void, shared_from_this()));
std::thread thread(boost::bind(&object::workerThread, this));
func_int(1);
func_int(1);
func_void();
func_void(); // Will crash due to shared_ptr being NULL, hence "value" cannot be accessed in handler_void
thread.join();
}
void handler_int(int parameter) {
cout << "handler_int: " << value << endl;
}
void handler_void() {
cout << "handler_void: " << value << endl;
}
boost::shared_ptr<boost::asio::io_service> service;
boost::shared_ptr<boost::asio::io_service::work> work;
boost::asio::strand strand;
std::function<void(int)> func_int;
std::function<void(void)> func_void;
int value;
};
int main(int argc, char *argv[]) {
boost::shared_ptr<object> obj(new object());
obj->run();
return 0;
}
最佳答案
这是由于误解了 wrap
的作用。这让我最近太着急了。我写信给 asio 的作者进行澄清。他告诉我的话让我吃惊。wrap
返回一个 'wrapped_handler' 但与您可能期望的相反, 这不是一个函数对象,它在 的掩护下执行调度。
它实际上是一个对象,其中包含您绑定(bind)的处理程序以及对执行程序的引用。 Asio io 对象在完成异步操作时使用此信息,以便在正确的上下文中执行处理程序。
令人困惑的是,这个 wrapped_handler
也有一个 operator()
。这只是执行绑定(bind)函数。它不发布或调度函数。在我看来,这个 operator()
不应该存在。我已经寄信给 Christopher Kohlhoff 表达了这一观点。我还没有得到答复。
你可以通过替换这个来证明这一点:
func_int(1);
有了这个:
service->post(strand->wrap(boost::bind(&object::handler_int, shared_from_this(), 1)));
对于绑定(bind)成员函数的每次调用。然后,您可以测试它们是否在链中执行。
请注意,您将它们发布/发送到哪个
io_service
无关紧要。它们将被直接发送到 wrap
与它们关联的链。最后,关于 asio 和 style。
您可能希望通过 shared_ptr 解决 io_service/strand/work 对象的所有权。这总是不必要的。 io_service 是应用程序的基本组件 - 中央消息循环。它不会有不确定的生命周期。工作或链也不会。如果您以下列方式结束其生命周期:
service.stop();
thread(s).join();
一切都会好起来。
关于c++ - boost::asio::strand wrap 导致来自 shared_from_this 的 shared_ptr 变为 NULL,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39220179/