boost::system::error_code::message()引发了带有boost::asio套接字的访问冲突



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

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类的多个实例中运行上面的代码,也就是说,当我遇到访问冲突问题时——当connect调用修改error_code时,error_code实例的内部成员m_cat似乎变为NULL,所以当我调用message()时,我得到了访问冲突。即使只有一个后台线程在运行,这种情况也会发生。

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

我运行的增强版本是1.50,因为这是用于在RAD工作室中构建64位应用程序的集成版本。

其他人在多线程设置中(在Embarcadero或其他版本中)遇到过这个问题吗?如果是,你是如何解决的?或者这个类在多线程方式中使用根本不安全?

这是一个很长的机会,但可能值得一试:

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

问题是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的编译器上保证是线程安全的,但如果编译器没有实现函数范围静态的线程安全初始化,这可能会中断。您可以通过跟踪对此函数的调用来轻松验证这一点,并查看是否存在潜在的竞争。

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

我喜欢这个带有ThreadPool的:使用boost asio 的线程池

你确定io_service->run()在某个地方被调用了吗?

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

来自boost文档:

默认构造的迭代器表示列表的末尾。

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

最新更新