【问题标题】:boost::system::error_code::message() throwing access violation exception with boost::asio socketboost::system::error_code::message() 使用 boost::asio 套接字抛出访问冲突异常
【发布时间】:2014-01-29 19:42:05
【问题描述】:

我正在实现一个客户端应用程序,它必须与硬件设备建立少量套接字连接。我已将问题分解为以下小代码子集

boost::system::error_code ec;
std::string str_message = ec.message();  // no access violation before connect()
std::string str_port = "502";
std::string str_ip = "192.168.12.198";

boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(),str_ip,str_port);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ip::tcp::socket s(io_service);

ec = s.connect(*iterator,ec);
if (ec)
{
    // connection error of some kind.
    std::string str_debug = ec.message();  // BANG!!!!

}

我正在使用 Embarcadero RAD studio XE4 C++ Builder,当我在主 VCL 线程中运行上述代码时,它工作正常。当我使用多个连接运行它时,上面的代码在TThread 类的多个实例中运行,这就是当我遇到访问冲突问题时 - 似乎当error_code 被@987654325 修改时@ 调用,error_code 实例的内部成员 m_cat 变为 NULL,因此当我调用 message() 时,我得到了访问冲突。即使我只有一个后台线程正在运行,也会发生这种情况。

我上面的代码是否有可能在我需要使用它的方式上根本不是线程安全的?我试图找出为什么这段代码不会在后台线程中运行,但找不到任何关于它的信息。

我运行的 boost 版本是 1.50,因为这是用于在 RAD studio 中构建 64 位应用程序的集成版本。

有没有其他人在多线程设置(在 Embarcadero 或其他)中遇到过这个问题,如果有,您是如何解决的?或者这个类在多线程中使用是不安全的?

【问题讨论】:

  • 两个问题:第一,当你说“让它在不同的线程中运行”时,每个线程都有自己的io_service吗?我假设他们有不同的地址,要连接的端口组合?其次,如果您知道地址和端口,您可以自己创建端点而不是解析查询。您是否检查过迭代器以实际包含任何端点?最后:我相信在使用迭代器时,您应该使用非成员 connect() boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/… 但是这可能是错误的。
  • @DeVadder 是的,每个线程都连接到不同的客户端计算机,每个线程都有自己的 io_service。我会看看你提供的链接。谢谢

标签: c++ multithreading boost-asio c++builder-xe4


【解决方案1】:

这有点远,但可能值得一试:

system::error_code 由两个条目组成:一个错误值和一个类别。错误值基本上只是一个int,但类别是Singleton。这是必需的,因为基于指针标识比较错误类别是否相等(即,当且仅当它们指向 same 类别对象时,两个类别才相等。

问题在于 Singleton 类别的初始化可能不是线程安全的。 Asio 使用system_category,在boost/libs/system/src/error_code.cpp 中实现。对于 1.50,实现如下所示:

BOOST_SYSTEM_DECL const error_category & system_category() BOOST_SYSTEM_NOEXCEPT
{
  static const system_error_category  system_category_const;
  return system_category_const;
}

这保证在符合 C++11 的编译器上是线程安全的,但如果您的编译器没有实现 thread-safe initialization of function-scope statics,这可能会中断。您可以通过跟踪对该函数的调用来轻松验证这一点,并查看您是否观察到潜在的竞争。

【讨论】:

  • 谢谢。这是迄今为止我得到的最有用的建议。我会看看这个。
【解决方案2】:

在多个示例中,它们在线程中调用 io_service->run(): http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/example/cpp11/futures/daytime_client.cpp

我喜欢这个,有一个线程池: Thread pool using boost asio

你确定 io_service->run() 在某处被调用吗?

【讨论】:

  • 我的印象是异步套接字而不是同步所需要的
【解决方案3】:

您必须始终确保iterator != boost::asio::ip::tcp::resolver::iterator()。

来自 boost 文档:

一个默认构造的迭代器表示列表的结尾。

我敢打赌这是问题所在,connect() 只是由于无效的端点迭代器而破坏了堆栈。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    • 2012-08-25
    相关资源
    最近更新 更多