15

I have a std::future in one thread which is waiting on a std::promise being set in another thread.

EDIT: Updated the question with an exemplar app which will block forever:

UPDATE: If I use a pthread_barrier instead, the below code does not block.

I have created a test-app which illustrates this:

Very basically class foo creates a thread which sets a promise in its run function, and waits in the constructor for that promise to be set. Once set, it increments an atomic count

I then create a bunch of these foo objects, tear them down, and then check my count.

#include <iostream>
#include <thread>
#include <atomic>
#include <future>
#include <list>
#include <unistd.h>

struct foo
{
    foo(std::atomic<int>& count)
        : _stop(false)
    {
        std::promise<void> p;
        std::future <void> f = p.get_future();

        _thread = std::move(std::thread(std::bind(&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<void>& 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 << "usage: " << argv[0] << " num_threads" << std::endl;
        return 1;
    }
    int num_threads = atoi(argv[1]);
    std::list<foo*> threads;
    std::atomic<int> count(0); // count will be inc'd once per thread

    std::cout << "creating threads" << std::endl;
    for (int i = 0; i < num_threads; ++i)
        threads.push_back(new foo(count));

    std::cout << "stopping threads" << std::endl;
    for (auto f : threads)
        f->_stop = true;

    std::cout << "joining threads" << std::endl;
    for (auto f : threads)
    {
        if (f->_thread.joinable())
            f->_thread.join();
    }

    std::cout << "count=" << count << (num_threads == count ? " pass" : " fail!") << std::endl;
    return (num_threads == count);
}

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 futures is never woken up, and therefore the app gets stuck forever.

# this loop never completes
$ for i in {1..1000}; do ./a.out 1000; done

If I now SIGABRT the app, the resulting stack trace shows it's stuck on the future::wait The stack trace is below:

// main thread
    pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
    __gthread_cond_wait (__mutex=<optimized out>, __cond=<optimized out>) at libstdc++-v3/include/x86_64-unknown-linux-gnu/bits/gthr-default.h:846
    std::condition_variable::wait (this=<optimized out>, __lock=...) at ../../../../libstdc++-v3/src/condition_variable.cc:56
    std::condition_variable::wait<std::__future_base::_State_base::wait()::{lambda()#1}>(std::unique_lock<std::mutex>&, 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<void>::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 <__once_proxy@plt>) at gthr-default.h:718
    std::call_once<void (std::__future_base::_State_base::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>&, bool&), std::__future_base::_State_base* const, std::reference_wrapper<std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()> >, std::reference_wrapper<bool> >(std::once_flag&, void (std::__future_base::_State_base::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, ...) at include/c++/4.7.0/mutex:819
    std::promise<void>::set_value (this=0x7fff32587880) at include/c++/4.7.0/future:1206
    foo::run (this=0x938320, p=...) at main.cpp:26

I'm pretty sure that I'm not doing anything wrong in my code, right?

Is this an issue with the pthread implementation, or the std::future/std::promise implementation?

My library versions are:

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)
Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
  • Can we see more of the internals of `send_promise`? – Anthony Jun 01 '12 at 04:05
  • @anthony-arnold, further details added in the body of the op – Steve Lorimer Jun 01 '12 at 04:30
  • Er, when is `Wait::_p` initialized? I don't see it. – ildjarn Jun 01 '12 at 04:43
  • @ildjarn, it will be default constructed when the Wait object is created – Steve Lorimer Jun 01 '12 at 04:47
  • @ildjarn, reference documentation which leads me to believe default construction is sufficient: http://www.stdthread.co.uk/doc/headers/future/promise/default_constructor.html – Steve Lorimer Jun 01 '12 at 04:48
  • @lori I still don't see the interaction of send_promise with the run function, maybe you can show that. Beside that make sure that in your loop or anywhere else you may call `set_value` and `get_future` on every promise only once. – Stephan Dollberg Jun 01 '12 at 05:33
  • @bamboon run is called in the context of thread 1. It creates a `Wait` instance (which has a std::promise member), posts a `std::function` which is bound to the Wait instance's `execute` member function to thread 2, and then waits on the `std::future` which is obtained from the Wait instance. Thread 2 executes the `std::function`, which calls `std::promise::set_value`. The object lifetime exists as long as thread 1 is waiting on the future, which will be signalled only when thread 2 calls the `Wait::execute` member function – Steve Lorimer Jun 01 '12 at 05:38
  • @bamboon - I've added some comments in the `run(...)` function to provide context – Steve Lorimer Jun 01 '12 at 05:41
  • Which platform are you using, GNU/Linux? `std::call_once` uses a different implementation depending on whether the platform supports TLS, and I can't see another reason for `pthread_once` to block like that. I _think_ the GCC 4.7 implementation of `promise::set_value()` is correct (but I would say that, I wrote it.) – Jonathan Wakely Jun 01 '12 at 12:27
  • I copied that `run` function and filled in the blanks and it works fine for me on a newer linux machine with glibc 2.11, but not on an older one with glibc 2.5, I get the same problem in `pthread_once`. I'll investigate tonight. – Jonathan Wakely Jun 01 '12 at 13:29
  • @JonathanWakely, thanks for the input. I am using glibc 2.11; it would suggest that I have a bug elsewhere which is causing this behaviour - I will investigate further. – Steve Lorimer Jun 03 '12 at 23:19
  • @JonathanWakely, I have updated the question with an exemplar which shows the issue – Steve Lorimer Jul 12 '12 at 01:53
  • `std::move(std::thread(std::bind(&foo::run, this, std::ref(p))))` should be simply `std::thread(&foo::run, this, std::ref(p))`, you don't need to use `std::move` on an rvalue and `thread` behaves like `bind` anyway. `foo::_stop` needs to be an `atomic`. Calling `joinable()` is unnecessary, the threads must be joinable at that point. – Jonathan Wakely Jul 12 '12 at 17:00

2 Answers2

8

Indeed, there is a race condition between the destructor of the local promise object (at the end of the constructor and the call to set_value() from the thread. That is, set_value() wakes the main tread, that just next destroys the promise object, but the set_value() function has not yet finished, and dead-locks.

Reading the C++11 standard, I'm not sure if your use is allowed:

void promise<void>::set_value();

Effects: atomically stores the value r in the shared state and makes that state ready.

But somewhere else:

The set_value, set_exception, set_value_at_thread_exit, and set_exception_at_thread_exit member functions behave as though they acquire a single mutex associated with the promise object while updating the promise object.

Are set_value() calls supposed to be atomic with regards to other functions, such as the destructor?

IMHO, I'd say no. The effects would be comparable to destroying a mutex while other thread is still locking it. The result is undefined.

The solution would be to make p outlive the thread. Two solutions that I can think of:

  1. Make p a member of the class, just as Michael Burr suggested in the other answer.

  2. Move the promise into the thread.

In the constructor:

std::promise<void> p;
std::future <void> f = p.get_future();
_thread = std::thread(&foo::run, this, std::move(p));

BTW, you don't need the call to bind, (the thread constructor is already overloaded), or call to std::move to move the thread (the right value is already an r-value). The call to std::move into the promise is mandatory, though.

And the thread function does not receive a reference, but the moved promise:

void run(std::promise<void> p)
{
    p.set_value();
}

I think that this is precisely why C++11 defines two different classes: promise and future: you move the promise into the thread, but you keep the future to recover the result.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • Hmm, [futures.state]/9 says making the state ready (in `p.set_value()`) synchronizes with the return from `f.wait()` so the promise _shouldn't_ be destroyed until the value has been set ... but changing the code to move the promise _does_ seem to fix the bug. I'll have to review my implementation of `promise::set_value()` ... – Jonathan Wakely Jul 12 '12 at 17:10
  • 2
    Ah, but `p.set_value()` makes the state ready _then_ wakes any waiting threads ([futures.state]/6). If the state is made ready _before_ the constructor starts waiting, then `f.wait()` returns immediately and `p` is destroyed, then the other thread tries to wake blocked threads, after the promise has been destroyed. So I think you've correctly identified the problem. – Jonathan Wakely Jul 12 '12 at 17:14
  • 1
    However, as the stack trace shows, when it hangs the constructor is still waiting on `f.wait()` so the promise hasn't been destroyed yet... odd. – Jonathan Wakely Jul 12 '12 at 17:46
  • 1
    @Jonathan: I suspect (actually more like a wild guess) that the never completing `f.wait()` is subsequent to the one involved in the race, and that it's never completing because the previous race corrupted something in the `pthread` library. – Michael Burr Jul 12 '12 at 18:43
  • Yes I came to the same conclusion – Jonathan Wakely Jul 12 '12 at 18:51
  • @rodrigo - accepting this as the answer, because using `move` means I don't need to make the `promise` a member. Since its usage is only to block the calling thread until the new thread has started, moving it means its lifetime more closely matches its use-case – Steve Lorimer Jul 12 '12 at 23:21
5

Try moving the std::promise<void> p; so that instead of being local to the constructor it will be a member of struct foo:

struct foo
{
    foo(std::atomic<int>& count)
        : _stop(false)
    {
        // std::promise<void> p;    // <-- moved to be a member
        std::future <void> f = p.get_future();

        // ...same as before...
    }
    void run(std::promise<void>& p)
    {
        // ... same ...
    }

    std::promise<void> p;   // <---
    std::thread _thread;
    bool _stop;
};

I beleive that what may be happening is that you get into a race where p is destroyed in the constructor while p.set_value() is acting on the reference to that promise. Something occurs inside set_value() while it's finishing up/cleaning up; acting on the reference to the already destroyed std::promise is corrupting some state in the pthread library.

This is just speculation - I don't have ready access to a system that reproduces the problem at the moment. But making p a member will ensure its lifetime extends well past the completion of the set_value() call.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • But the code does not leave the constructor before the threads calls p.set_value(). It is waiting – fork0 Jul 12 '12 at 08:45
  • 1
    @fork0: But once unblocked, the constructor might finish before `set_value()` returns. Note that I'm not sure there's a race there (or that a race is permitted there by the standard), but it looks like an area where there could be a problem if `set_value` uses some state from `p` after it has performed whatever signalling will unblock the wait on the future. Also, even if that turns out to be the case, I'm not sure if that would be a bug somewhere in the implementation of `set_value` or the `pthread` APIs it relies on, or a bug in how the `promise` is used in the code here. – Michael Burr Jul 12 '12 at 08:52
  • Ah, right. OF, the implementation can be dependent. Arguably, a broken implementation – fork0 Jul 12 '12 at 09:33
  • @fork0, I think there's a race even with a correct implementation, see my second comment to [rodrigo's answer](http://stackoverflow.com/a/11448290/981959) – Jonathan Wakely Jul 12 '12 at 17:16
  • 2
    The standard requires that `promise::set_value()` hold a mutex (or act as if a mutex is held) while it's updating the `promise` object (30.6.5/2). If the `promise` gets destroyed while `set_value` is holding a mutex in the `promise` object, surely that results in UB. Therefore, it's not safe for the `promise` to be destroyed until *after* `promise::set_value()` returns and the `promise` reference is no longer used. I agree with Jonathan that the implementation is not required to make `promise::set_value()` safe in the face of the `promise` being destroyed while `set_value()` is still active. – Michael Burr Jul 12 '12 at 17:51
  • And in fact valgrind shows `pthread_once` gets called on deallocated memory freed by `~promise`. +1 on all Michael's comments for spotting the race, I missed that and was assuming there was a bug in my `` impl! – Jonathan Wakely Jul 12 '12 at 18:00