C++ boost::property_tree::ptree是线程安全的吗?

C++ boost::property_tree::ptree是线程安全的吗?,c++,json,boost,thread-safety,segmentation-fault,C++,Json,Boost,Thread Safety,Segmentation Fault,我在一段代码的几个线程中使用boosts read_json。下面是电话的简单分类。我在其中一个线程中(有时在另一个线程中)遇到了segfaults,这让我觉得read_json不是线程安全的(或者我只是以一种愚蠢的方式使用它) 现在两个类之间的json_data_字符串不同了(它只是通过套接字接收的json数据) 那么,read_json是线程安全的,还是我必须对其进行互斥(而不是互斥),还是有更好的方法调用线程安全的read_json?TL;博士: 我的建议是:使用原子交换习惯用法 ptre

我在一段代码的几个线程中使用boosts read_json。下面是电话的简单分类。我在其中一个线程中(有时在另一个线程中)遇到了segfaults,这让我觉得read_json不是线程安全的(或者我只是以一种愚蠢的方式使用它)

现在两个类之间的json_data_字符串不同了(它只是通过套接字接收的json数据)

那么,read_json是线程安全的,还是我必须对其进行互斥(而不是互斥),还是有更好的方法调用线程安全的read_json?

TL;博士:

我的建议是:使用原子交换习惯用法

ptree my_shared;
mutex shared_ptree_lock;

{
    ptree parsed;     // temporary
    read_json(ss,pt); // this may take a while (or even fail)

    lock_guard hold(shared_ptree_lock);
    std::swap(pt, my_shared); // swap under lock
}
现在,阅读之前是否需要锁定共享树取决于您对线程上下文的了解(换句话说,取决于您是否知道可以同时修改树)

要使事情变得异常灵活,可以通过
shared\ptr
执行同样的操作,但这将承担相当大的开销。pre是,使用swap习惯用法,您不必在读取端锁定内容,因为读者会很高兴地继续阅读这棵老树,如果他们完成了阅读并释放了
shared\u ptr
,它最终会被销毁


我不完全确定你期望什么。如果从两个线程访问属性树进行写操作,那么如果没有锁定,它将永远不会是线程安全的。因此,我假设您的意思是,当在其他地方同时解析属性树时,它是线程安全的

<> P>这里,我的主要期望是:不,C++有一种“为你所需要的付出”的文化,你不会看到任何线程安全的通用类。我们可以选择

  • 一个预处理器#define打开线程安全
  • 控制行为的策略模板参数

在查看源代码之后,令人惊讶的是,它看起来几乎是线程安全的。但并非完全如此:)

似乎没有要设置的#define或标志来确保属性树线程安全,因此您只能使用锁定

理论基础: 查看
internal\u read\u json
我发现它只访问流(无论如何,这对这个读者来说应该是私有的,因为跨多个(并发)用户共享流几乎没有用1),然后,非常正确地说,只将ptree的(
pt
)根节点与解析器的上下文树交换

显然,原子交换功能主要是为了异常安全(如果在解析JSON的过程中发生异常,您不想更改ptree)。但是,如果交换操作是线程安全的,这也会使对
pt
的访问是线程安全的

唉,在ptree_实现中,我们看到交换不是线程安全的:

template<class K, class D, class C> inline
void basic_ptree<K, D, C>::swap(basic_ptree<K, D, C> &rhs)
{
    m_data.swap(rhs.m_data);
    // Void pointers, no ADL necessary
    std::swap(m_children, rhs.m_children);
}
模板内联
作废基本目录::交换(基本目录和rhs)
{
m_数据交换(rhs.m_数据);
//无效指针,无需ADL
标准::交换(m_儿童,rhs.m_儿童);
}
首先,在交换
m_数据
m_子数据
之间可能存在竞争条件,而且,交换是标准的,而不是原子交换



1besides
istringstream
显然不是线程安全的,因为它是C++98标准库类

,因为boost json解析器依赖于boost::spirit,而spirit不是线程安全默认值

您可以在任何ptree头文件之前添加此宏来解析它

#define BOOST_SPIRIT_THREADSAFE
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#定义BOOST_SPIRIT_THREADSAFE
#包括
#包括

感谢伟和蓝海;“定义”解决了我的问题。仅供参考,我正在从windbg获取堆栈跟踪!当我有两个线程调用read_json时分析-v

10 07b3e4fc 0021b2de sseng!_STL::for_each<_STL::reverse_iterator<boost::spirit::classic::impl::grammar_helper_base<boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> > > * *>,_STL::binder2nd<_STL::mem_fun1_t<int,boost::spirit::classic::impl::grammar_helper_base<boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> > >,boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> > *> > >+0x11 [c:\ss\tp\aoo341\main\stlport\rel\inc\stlport\stl\_algo.h @ 65]
11 07b3e520 0021f867 sseng!boost::spirit::classic::impl::grammar_destruct<boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> > >+0x28 [c:\ss\tp\aoo341\main\boost\rel\inc\boost\spirit\home\classic\core\non_terminal\impl\grammar.ipp @ 325]
12 07b3e54c 002224fa sseng!boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> >::~grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> >+0x1e [c:\ss\tp\aoo341\main\boost\rel\inc\boost\spirit\home\classic\core\non_terminal\grammar.hpp @ 52]
13 07b3e574 00226e37 sseng!boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >::~json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >+0x28
14 07b3e784 00226f5c sseng!boost::property_tree::json_parser::read_json_internal<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >+0x149 [c:\ss\tp\aoo341\main\boost\rel\inc\boost\property_tree\detail\json_parser_read.hpp @ 317]
15 07b3e7c0 00232261 sseng!boost::property_tree::json_parser::read_json<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >+0x25 [c:\ss\tp\aoo341\main\boost\rel\inc\boost\property_tree\json_parser.hpp @ 45]
16 07b3ea20 00232a28 sseng!SSPhone::Handshake+0x15b [c:\ss\xl\src\cpp\bin\eng\ssphone.cpp @ 272]
17 07b3ea5c 00234fc7 sseng!SSPhone::OnEvent+0x1a9 [c:\ss\xl\src\cpp\bin\eng\ssphone.cpp @ 232]
18 07b3fb7c 6f6b3433 sseng!PhoneThreadFunc+0x1ed [c:\ss\xl\src\cpp\bin\eng\ssthrd.cpp @ 198]
10 07b3e4fc 0021b2de sseng_STL::for_each+0x11[c:\ss\tp\aoo341\main\stlport\rel\inc\stlport\STL\\u algo.h@65]
11 07b3e520 0021f867 SSEN!boost::spirit::classic::impl::grammar\u destruct+0x28[c:\ss\tp\aoo341\main\boost\rel\inc\boost\spirit\home\classic\core\non\u terminal\impl\grammar.ipp@325]
12 07b3e54c 00224Fa sseng!boost::spirit::classic::grammar::~grammar+0x1e[c:\ss\tp\aoo341\main\boost\rel\inc\boost\spirit\home\classic\core\non\u terminal\grammar.hpp@52]
13 07b3e574 00226e37 sseng!boost::property_tree::json_解析器::json_语法::~json_语法+0x28
14 07b3e784 00226f5c sseng!boost::property\u tree::json\u parser::read\u json\u internal+0x149[c:\ss\tp\aoo341\main\boost\rel\inc\boost\property\u tree\detail\json\u parser\u read.hpp@317]
15 07b3e7c0 00232261 sseng!boost::property_tree::json_parser::read_json+0x25[c:\ss\tp\aoo341\main\boost\rel\inc\boost\property_tree\json_parser.hpp@45]
16 07b3ea20 00232a28 ASSENG!SSPhone::Handshake+0x15b[c:\ss\xl\src\cpp\bin\eng\SSPhone.cpp@272]
17 07b3ea5c 00234fc7 sseng!SSPhone::OnEvent+0x1a9[c:\ss\xl\src\cpp\bin\eng\SSPhone.cpp@232]
18 07b3fb7c 6f6b3433 sseng!PhoneThreadFunc+0x1ed[c:\ss\xl\src\cpp\bin\eng\ssthrd.cpp@198]

ptree中的JSON解析器已被重写,并在Boost 1.59中发布。属性树不再需要添加
BOOST\u SPIRIT\u THREADSAFE
define,因为它不再使用
BOOST。SPIRIT
read\u json
函数可能被认为是线程安全的。

是的,我实际上是在尝试从两个单独的线程(在独立数据上)使用read\u json函数。我猜他们调用的是内存中的同一个函数(net是一个单独的实例),因此segfault-damn…@RossW:听起来很困惑。函数必须相同(只有一个二进制),但它们不能相互干扰(它们位于不同的堆栈、不同的线程上)。冲突只能由对输入流或pt输出参数的访问引起。共享时,您需要同步对它们的访问。更重要的是,你将不得不考虑生命周期(对老树的破坏将使任何指向它内部的指针/引用失效)。这也是我的想法,这就是为什么我对此感到困惑的原因。我将尝试简化代码的版本,看看我得到了什么好的,所以我做了一个
10 07b3e4fc 0021b2de sseng!_STL::for_each<_STL::reverse_iterator<boost::spirit::classic::impl::grammar_helper_base<boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> > > * *>,_STL::binder2nd<_STL::mem_fun1_t<int,boost::spirit::classic::impl::grammar_helper_base<boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> > >,boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> > *> > >+0x11 [c:\ss\tp\aoo341\main\stlport\rel\inc\stlport\stl\_algo.h @ 65]
11 07b3e520 0021f867 sseng!boost::spirit::classic::impl::grammar_destruct<boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> > >+0x28 [c:\ss\tp\aoo341\main\boost\rel\inc\boost\spirit\home\classic\core\non_terminal\impl\grammar.ipp @ 325]
12 07b3e54c 002224fa sseng!boost::spirit::classic::grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> >::~grammar<boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >,boost::spirit::classic::parser_context<boost::spirit::classic::nil_t> >+0x1e [c:\ss\tp\aoo341\main\boost\rel\inc\boost\spirit\home\classic\core\non_terminal\grammar.hpp @ 52]
13 07b3e574 00226e37 sseng!boost::property_tree::json_parser::json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >::~json_grammar<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >+0x28
14 07b3e784 00226f5c sseng!boost::property_tree::json_parser::read_json_internal<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >+0x149 [c:\ss\tp\aoo341\main\boost\rel\inc\boost\property_tree\detail\json_parser_read.hpp @ 317]
15 07b3e7c0 00232261 sseng!boost::property_tree::json_parser::read_json<boost::property_tree::basic_ptree<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::less<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > >+0x25 [c:\ss\tp\aoo341\main\boost\rel\inc\boost\property_tree\json_parser.hpp @ 45]
16 07b3ea20 00232a28 sseng!SSPhone::Handshake+0x15b [c:\ss\xl\src\cpp\bin\eng\ssphone.cpp @ 272]
17 07b3ea5c 00234fc7 sseng!SSPhone::OnEvent+0x1a9 [c:\ss\xl\src\cpp\bin\eng\ssphone.cpp @ 232]
18 07b3fb7c 6f6b3433 sseng!PhoneThreadFunc+0x1ed [c:\ss\xl\src\cpp\bin\eng\ssthrd.cpp @ 198]