繁体   English   中英

boost::property_tree::ptree 线程安全吗?

[英]is boost::property_tree::ptree thread safe?

我在一段代码的几个线程中使用 boosts read_json。 通话的简化细分如下。 我在其中一个线程(有时是另一个)中遇到段错误,这让我认为 read_json 不是线程安全的(或者我只是在以一种愚蠢的方式使用它)

void someclass::dojson() {
   using boost::property_tree::ptree;
   ptree pt;
   std::stringstream ss(json_data_string);

   read_json(ss,pt);
 }

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

那么 read_json 线程安全还是我必须互斥它(而不是)或者有更好的调用 read_json 线程安全的方法吗?

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

你可以在任何 ptree 头文件之前添加这个宏来解决它。

#define BOOST_SPIRIT_THREADSAFE
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

特尔;博士:

我的建议:使用原子交换习语

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<ptree>做同样的事情 - 但这将承担相当大的开销。 前提是,使用交换习惯用法,您不必在读取端锁定内容,因为读者会很高兴地继续读取旧树,如果他们完成读取并释放shared_ptr它将最终被销毁.


我不完全确定你的期望。 由于从两个线程访问属性树以进行写入,没有锁定就永远不会是线程安全的。 因此,我假设您的意思是,属性树是线程安全的,可以在读取的同时在其他地方解析它。

在这里,我的主要期望是:不。 C++ 具有“按需付费”的文化,您将看不到任何线程安全的通用类。 会有这样的选择

  • 一个预处理器 #define 来开启线程安全
  • 管理行为的策略模板参数

查看源代码后,令人惊讶的是,它看起来几乎是线程安全的。 但不完全:)

似乎没有设置 #define 或标志来使属性树线程安全,因此您无法使用锁定。

理由:

查看internal_read_json我看到它只访问流(无论如何应该是这个读者私有的,因为在多个(并发)用户之间共享流几乎没有用1 ),然后,非常正确,只交换 ptree 的( pt )根节点与解析器的上下文树。

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

唉,在 ptree_implementation 上,我们看到交换不是线程安全的:

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);
}

一方面,您可能在交换m_datam_children之间存在竞争条件,此外,交换是标准的,而不是原子交换。


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

ptree 中的 JSON 解析器已在 Boost 1.59 中重写和发布。 属性树不再需要添加BOOST_SPIRIT_THREADSAFE定义,因为它不再使用Boost.Spirit并且read_json函数可能被认为是线程安全的。

感谢 Wei 和 Liquidblueocean; #define 解决了我的问题。 仅供参考,当我有两个线程调用 read_json 时,我从windbg !analysis -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]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM