【问题标题】:Access violation while "spamming" boost::property_tree::read_json“垃圾邮件” boost::property_tree::read_json 时访问冲突
【发布时间】:2013-08-19 11:38:03
【问题描述】:

我使用 Boost Asio (1.53.0) 制作了一个简单的 TCP 服务器。服务器接受 JSON 请求,使用 boost::property_tree::read_json 解析它们。

为了测试可靠性,我创建了一个简单的应用程序,它创建了 128 个线程并不断发送请求。

几秒钟后,服务器因访问冲突而崩溃:

Unhandled exception at 0x000007FEFD829E5D (KernelBase.dll) in RPC_Server.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

msvcr110d.dll!__RethrowException(EHExceptionRecord * pThisException) Line 1217
msvcr110d.dll!__CxxCallCatchBlock(_EXCEPTION_RECORD * pExcept) Line 1279
ntdll.dll!0000000077360c21()
RPC_Server.exe!json::json::Parse(std::basic_string<char,std::char_traits<char>,std::allocator<char> > & sJson) Line 28

这里调用了 read_json:

rpc::request json::Parse(std::string sJson)
{
  try {
    std::stringstream ss;
    ss << sJson;
    boost::property_tree::ptree pt;
    boost::property_tree::read_json(ss, pt);
...
}
  • 如果我注释掉 read_json 行,服务器会处理所有事情 正确。
  • 如果我将测试应用程序减少到例如只有1个线程, 服务器正确处理和解析所有内容。

【问题讨论】:

  • 我注意到您将sJson 作为参考。字符串本身存储在哪里?是否可以与其他线程共享(并被其他线程修改)?
  • 也试过By-Value,没关系。
  • 作为一个实验,将线程数减少到只有一个。如果发生这种情况以消除访问冲突,那么这意味着问题很可能是由于多线程问题造成的。如果可行,则再次增加线程,但在 read_json 代码周围放置一些关键部分或互斥锁。
  • 示例代码显示字符串参数作为副本传递,并且所有其他变量都已添加到堆栈中。线程无关紧要。当 read_json 完成时,我也会崩溃,如果我猛击它。

标签: c++ json boost boost-asio access-violation


【解决方案1】:

似乎 boost::property_tree::read_json 默认不是线程安全的。

你必须定义:

#define BOOST_SPIRIT_THREADSAFE

【讨论】:

  • 如果这解决了提问者的问题,那么这只是运气。示例代码显示了作为副本传递的字符串参数,并且所有其他变量都已添加到堆栈中。线程无关紧要。当 read_json 完成时,我也有这个崩溃,如果我猛击它。另一个例子是stackoverflow.com/questions/18837401/…
  • 好的,这是我的问题的答案:如果您没有全局定义它,但在多个独立的 cpps 中使用 Spirit/json_parser,它仍然会崩溃,因为恼人的 Sprit 有一个静态变量将在所有人之间共享。这有点垃圾...... BOOST_SPIRIT_THREADSAFE 应该默认开启。
  • 很高兴听到你解决了它。是的,它绝对应该默认开启!
猜你喜欢
  • 1970-01-01
  • 2012-09-14
  • 2011-09-06
  • 2014-02-28
  • 2017-09-06
  • 2012-12-31
  • 1970-01-01
  • 1970-01-01
  • 2016-11-07
相关资源
最近更新 更多