Ros*_*s W 18 c++ json boost thread-safety segmentation-fault
我在一段代码中的几个线程中使用了boost read_json.简化的呼叫细分如下.我在其中一个线程(有时是另一个)中得到段错误,这让我觉得read_json不是线程安全的(或者我只是以愚蠢的方式使用它)
void someclass::dojson() {
using boost::property_tree::ptree;
ptree pt;
std::stringstream ss(json_data_string);
read_json(ss,pt);
}
Run Code Online (Sandbox Code Playgroud)
现在json_data_string在两个类之间是不同的(它只是通过套接字接收的json数据).
那么read_json线程是安全的还是我必须互斥它(而不是)或者是否有更好的方法来调用线程安全的read_json?
小智 19
因为boost json解析器依赖于boost :: spirit,而spirit不是线程安全默认的.
您可以在任何ptree头文件之前添加此宏来解决它.
#define BOOST_SPIRIT_THREADSAFE
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
Run Code Online (Sandbox Code Playgroud)
TL; DR:
我的建议:使用原子交换习语
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
}
Run Code Online (Sandbox Code Playgroud)
现在,您是否需要在读取之前锁定共享树,取决于您对线程上下文的了解(换句话说,取决于您是否知道您的树可以同时被修改).
为了使事情变得非常灵活,做同样的事情shared_ptr<ptree>- 但这会带来相当大的开销.前者是,使用交换习语,你不必在阅读方面锁定东西,因为读者会愉快地继续读取旧树,如果它们完成阅读并释放shared_ptr它,它最终会被破坏.
我不完全确定你的期望.对于从两个线程进行写入访问的属性树,在没有锁定的情况下永远不会是线程安全的.因此,我认为你的意思是,属性树线程安全的读取,同时解析它在其他地方.
在这里,我的主要期望是:不.C++有一种"按需购买"的文化,你不会看到任何线程安全的通用类.可以选择
看完源代码后,令人惊讶的是,它看起来好像几乎是线程安全的.但不完全:)
似乎没有#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);
}
Run Code Online (Sandbox Code Playgroud)
首先,你可以有交换之间的竞争条件m_data和m_children,进一步,掉期是标准的,不是原子互换.
1除了istringstream显然不是线程安全的,因为它是一个C++ 98标准库类
| 归档时间: |
|
| 查看次数: |
5850 次 |
| 最近记录: |