Opened 8 years ago
Closed 8 years ago
#10478 closed Bugs (fixed)
Data race in boost/thread/future.hpp
Reported by: | Owned by: | viboes | |
---|---|---|---|
Milestone: | Boost 1.57.0 | Component: | thread |
Version: | Boost 1.56.0 | Severity: | Problem |
Keywords: | future, shared state | Cc: |
Description
Non-static member function "mark_finished_with_result" of class template "future_async_shared_state" (inherited from "future_async_shared_state_base") is called from static member function "run" concurrently with constructor. Newly created thread uses the object being constructed by original thread. This is data race condition and results in undefined behavior [1.10.21, std-2011]. Moreover, the call of "mark_finished_with_result" may be completed even before constructor execution begins, which also leads to undefined behavior [12.7.1, std-2011].
Program below illustrates the problem:
#define BOOST_THREAD_VERSION 4 #include <iostream> #include <boost/thread.hpp> void func(int num) { //boost::this_thread::yield(); if (num == 0) return; std::cout << 'A' << num << std::endl; async(boost::launch::async, func, num - 1); std::cout << 'B' << num << std::endl; } int main() { func(3); }
Under QNX 6.5.0 SP1 with gcc 4.8.3 it gives the following:
A3 A2 A1 In function notify_all -- d:/boost_1_56_0/boost/thread/pthread/condition_variable.hpp:142 !pthread_cond_broadcast(&cond) -- assertion failed
After uncommenting the call of yield we get what’s expected:
A3 A2 A1 B1 B2 B3
Possible solution for C++11 is to create new thread in the body of "future_async_shared_state" constructor instead of using member initializer syntax for base:
--- future.hpp Mon Aug 4 00:58:54 2014 +++ future-fixed.hpp Thu Sep 4 13:00:54 2014 @@ -882,5 +882,5 @@ public: - explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) : - base_type(thread(&future_async_shared_state::run, this, boost::forward<Fp>(f))) + explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) { + thr_ = thread(&future_async_shared_state::run, this, boost::forward<Fp>(f)); } @@ -912,5 +912,5 @@ public: - explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) : - base_type(thread(&future_async_shared_state::run, this, boost::forward<Fp>(f))) + explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) { + thr_ = thread(&future_async_shared_state::run, this, boost::forward<Fp>(f)); }
Change History (4)
comment:1 by , 8 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:2 by , 8 years ago
Yes, after applying the patch sample program runs normally with and without "yield". Maybe it's also reasonable to remove constructor of "future_async_shared_state_base" taking "thread" as parameter.
comment:3 by , 8 years ago
Milestone: | To Be Determined → Boost 1.57.0 |
---|
comment:4 by , 8 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
Thanks for catching this data race condition :)
Have you checked if your patch fixes the issue?