Note that there are some explanatory texts on larger screens.

plurals
  1. POrace-condition in pthread_once()?
    text
    copied!<p>I have a <code>std::future</code> in one thread which is waiting on a <code>std::promise</code> being set in another thread. </p> <p><strong>EDIT:</strong> <em>Updated the question with an exemplar app which will block forever:</em></p> <p><strong>UPDATE:</strong> If I use a <code>pthread_barrier</code> instead, the below code does <strong>not</strong> block.</p> <p>I have created a test-app which illustrates this:</p> <p>Very basically class <code>foo</code> creates a <code>thread</code> which sets a <code>promise</code> in its run function, and waits in the constructor for that <code>promise</code> to be set. Once set, it increments an <code>atomic</code> count</p> <p>I then create a bunch of these <code>foo</code> objects, tear them down, and then check my <code>count</code>.</p> <pre><code>#include &lt;iostream&gt; #include &lt;thread&gt; #include &lt;atomic&gt; #include &lt;future&gt; #include &lt;list&gt; #include &lt;unistd.h&gt; struct foo { foo(std::atomic&lt;int&gt;&amp; count) : _stop(false) { std::promise&lt;void&gt; p; std::future &lt;void&gt; f = p.get_future(); _thread = std::move(std::thread(std::bind(&amp;foo::run, this, std::ref(p)))); // block caller until my thread has started f.wait(); ++count; // my thread has started, increment the count } void run(std::promise&lt;void&gt;&amp; p) { p.set_value(); // thread has started, wake up the future while (!_stop) sleep(1); } std::thread _thread; bool _stop; }; int main(int argc, char* argv[]) { if (argc != 2) { std::cerr &lt;&lt; "usage: " &lt;&lt; argv[0] &lt;&lt; " num_threads" &lt;&lt; std::endl; return 1; } int num_threads = atoi(argv[1]); std::list&lt;foo*&gt; threads; std::atomic&lt;int&gt; count(0); // count will be inc'd once per thread std::cout &lt;&lt; "creating threads" &lt;&lt; std::endl; for (int i = 0; i &lt; num_threads; ++i) threads.push_back(new foo(count)); std::cout &lt;&lt; "stopping threads" &lt;&lt; std::endl; for (auto f : threads) f-&gt;_stop = true; std::cout &lt;&lt; "joining threads" &lt;&lt; std::endl; for (auto f : threads) { if (f-&gt;_thread.joinable()) f-&gt;_thread.join(); } std::cout &lt;&lt; "count=" &lt;&lt; count &lt;&lt; (num_threads == count ? " pass" : " fail!") &lt;&lt; std::endl; return (num_threads == count); } </code></pre> <p>If I run this in a loop with 1000 threads, it only has to execute it a few times until a race occurs and one of the <code>futures</code> is never woken up, and therefore the app gets stuck forever.</p> <pre><code># this loop never completes $ for i in {1..1000}; do ./a.out 1000; done </code></pre> <p>If I now <code>SIGABRT</code> the app, the resulting stack trace shows it's stuck on the <code>future::wait</code> The stack trace is below:</p> <pre><code>// main thread pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0 __gthread_cond_wait (__mutex=&lt;optimized out&gt;, __cond=&lt;optimized out&gt;) at libstdc++-v3/include/x86_64-unknown-linux-gnu/bits/gthr-default.h:846 std::condition_variable::wait (this=&lt;optimized out&gt;, __lock=...) at ../../../../libstdc++-v3/src/condition_variable.cc:56 std::condition_variable::wait&lt;std::__future_base::_State_base::wait()::{lambda()#1}&gt;(std::unique_lock&lt;std::mutex&gt;&amp;, std::__future_base::_State_base::wait()::{lambda()#1}) (this=0x93a050, __lock=..., __p=...) at include/c++/4.7.0/condition_variable:93 std::__future_base::_State_base::wait (this=0x93a018) at include/c++/4.7.0/future:331 std::__basic_future&lt;void&gt;::wait (this=0x7fff32587870) at include/c++/4.7.0/future:576 foo::foo (this=0x938320, count=...) at main.cpp:18 main (argc=2, argv=0x7fff32587aa8) at main.cpp:52 // foo thread pthread_once () from /lib64/libpthread.so.0 __gthread_once (__once=0x93a084, __func=0x4378a0 &lt;__once_proxy@plt&gt;) at gthr-default.h:718 std::call_once&lt;void (std::__future_base::_State_base::*)(std::function&lt;std::unique_ptr&lt;std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter&gt; ()&gt;&amp;, bool&amp;), std::__future_base::_State_base* const, std::reference_wrapper&lt;std::function&lt;std::unique_ptr&lt;std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter&gt; ()&gt; &gt;, std::reference_wrapper&lt;bool&gt; &gt;(std::once_flag&amp;, void (std::__future_base::_State_base::*&amp;&amp;)(std::function&lt;std::unique_ptr&lt;std::__future_base::_Result_base, ...) at include/c++/4.7.0/mutex:819 std::promise&lt;void&gt;::set_value (this=0x7fff32587880) at include/c++/4.7.0/future:1206 foo::run (this=0x938320, p=...) at main.cpp:26 </code></pre> <p>I'm pretty sure that I'm not doing anything wrong in my code, right? </p> <p>Is this an issue with the pthread implementation, or the std::future/std::promise implementation?</p> <p>My library versions are:</p> <pre><code>libstdc++.so.6 libc.so.6 (GNU C Library stable release version 2.11.1 (20100118)) libpthread.so.0 (Native POSIX Threads Library by Ulrich Drepper et al Copyright (C) 2006) </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload