【问题标题】:C++: boost io_context/strand wrap causes segment fault on shared_ptrC++:boost io_context/strand wrap 导致 shared_ptr 上的段错误
【发布时间】:2021-01-10 22:59:51
【问题描述】:

有人能帮我理解为什么我从代码 sn-p 得到以下结果吗?如果将 lambda 函数更改为至少采用 1 个参数:我得到了两次输出“valid ptr”。这是在我的代码中出现的段错误崩溃中发现的。

Output:
  valid ptr
  nullptr

#include <iostream>
#include <memory>
#include <boost/asio.hpp>

auto getWrapper(boost::asio::io_context& ioContext) 
{
    auto sharedPtr = std::make_shared<int>(0);
    return ioContext.wrap( [sharedPtr](){ 
                                          if(sharedPtr == nullptr) 
                                            std::cout << "nullptr\n";
                                          else
                                            std::cout << "valid ptr\n";
                                         });
}

int main()
{
    boost::asio::io_context ioContext;
    auto wrapper = getWrapper(ioContext);
    wrapper();
    wrapper();
    ioContext.run();
}

【问题讨论】:

  • 我对@9​​87654323@ 不是很熟悉,但据我了解,这意味着每个操作只执行一次。所以可能 lambda 在第一次执行 wrapper() 时被移动到执行程序,并使其在第二次执行时处于空状态。
  • 我也想过,如果是这样的话,处理程序的第二次执行不应该导致运行计时器错误,例如std::bad_function_call?我观察到的奇怪的事情是,如果 lambda 函数至少采用一个参数,那么一切似乎都可以正常工作。说'return [sharedPtr](int){ ... }'
  • 不一定有运行时检查。他们只是打电话给第二个电话 UB 什么的。无论如何,wrap 方法已被弃用。考虑使用他们在 boosr 文档中建议的替代方案。也许它没有被窃听。 (int 版本可能被一层boost::bind 包裹,它被移动到执行中——这就是原始 lambda 未被移动的原因。
  • 如果对您有帮助,请不要忘记接受答案。

标签: c++ boost segmentation-fault shared-ptr


【解决方案1】:

首先你必须实际使用一个链,io_context::wrap 已被弃用。 所以让我们写

#include <iostream>
#include <memory>
#include <boost/asio.hpp>

auto getScheduleWrapper(boost::asio::io_context::strand& strand)
{
    auto sharedPtr = std::make_shared<int>(0);
    return [sharedPtr, &strand] () {
    boost::asio::post(strand.context(),
                      boost::asio::bind_executor(strand, [sharedPtr] (){
                          if(sharedPtr == nullptr)
                              std::cout << "nullptr\n";
                          else
                              std::cout << "valid ptr\n";
                      }));
        };
}

int main()
{
    boost::asio::io_context ioContext;
    boost::asio::io_context::strand strand{ioContext};
    auto scheduleWrapper = getScheduleWrapper(strand);
    scheduleWrapper();
    scheduleWrapper();

    ioContext.run();
}

这将输出

valid ptr
valid ptr

正如预期的那样。但请注意:strands 并不保证计划任务会运行一次,而实际上您是在计划它们两次。它们“仅”保证在该链上一次只运行一个任务,并且它们将按照最初计划的顺序运行。

【讨论】:

  • 谢谢,boost::asio::bind_executor 完成了这项工作。看来return boost::asio::bind_executor(...) 就够了。
猜你喜欢
  • 2021-11-22
  • 1970-01-01
  • 2020-08-11
  • 1970-01-01
  • 2016-02-24
  • 2013-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多