A few days ago I noticed a lot of fast crashes of my program after adding multithreading to it. GDB showed the segfault in json_spirit::read(). So I wondered if that is a thread safety issue. I could not find any information about whether the json spirit package for ubuntu is thread safe or not. A simple test reproduces this behaviour:
#include
#include
#include
#include
void test()
{
json_spirit::mValue v;
for(int i = 0; i < 1000; ++i)
json_spirit::read("{}", v);
}
int main()
{
std::vector threads;
for(int i = 0; i < 8; ++i)
threads.emplace_back(test);
for (auto& th : threads)
th.join();
}
clang++ test.cxx -pthread -ljson_spirit -std=c++11 -O0 -g3
The test program crashes immediately at least on my system (Ubuntu 14.04, libjson-spirit-dev 4.05-1.1). The Backtrace looks like this:
#0 0x00007ffff0000960 in ?? ()
#1 0x000000000042e0de in __gnu_cxx::__normal_iterator json_spirit::read_range_or_throw<__gnu_cxx::__normal_iterator, json_spirit::Value_impl > >(__gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator, json_spirit::Value_impl >&) ()
#2 0x000000000042e1bc in bool json_spirit::read_range<__gnu_cxx::__normal_iterator, json_spirit::Value_impl > >(__gnu_cxx::__normal_iterator&, __gnu_cxx::__normal_iterator, json_spirit::Value_impl >&) ()
#3 0x00000000004080fd in json_spirit::read(std::string const&, json_spirit::Value_impl >&) ()
#4 0x00000000004028fb in test () at test.cxx:10
#5 0x0000000000404f3f in std::_Bind_simple::_M_invoke<>(std::_Index_tuple<>) (this=0x6f3060) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731
#6 0x0000000000404f15 in std::_Bind_simple::operator()() (this=0x6f3060) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720
#7 0x0000000000404eec in std::thread::_Impl >::_M_run() (this=0x6f3048) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115
#8 0x00007ffff7b87bf0 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#9 0x00007ffff73a4182 in start_thread (arg=0x7ffff6fd5700) at pthread_create.c:312
#10 0x00007ffff70d130d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
Adding a mutexed thread safe wrapper function which calls json_spirit::read() fixed the problem:
#include
#include
#include
#include
bool js_read(const std::string& js, json_spirit::mValue& v)
{
static std::mutex mtx;
std::lock_guard lock(mtx);
return json_spirit::read(js, v);
}
void test()
{
json_spirit::mValue v;
for(int i = 0; i < 1000; ++i)
js_read("{}", v);
}
int main()
{
std::vector threads;
for(int i = 0; i < 8; ++i)
threads.emplace_back(test);
for (auto& th : threads)
th.join();
}
Note that the initialization of the static local mutex is only thread safe since C++11. Alternativly you have to use a global mutex.