当我尝试使用boost::asio::strand wrap 函数时,似乎导致来自shared_ptrshared_from_this 变为NULL,所以当它第二次执行时,它会导致程序崩溃。

但是,这仅在绑定(bind)的函数采用 无参数 时才会发生。

设置观察点并检查调用堆栈后,此行为似乎是由 shared_ptr 交换值的移动构造函数引起的,该构造函数源自 async_result_initBOOST_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/

10-14 08:00