Is std::promise thread-safe?

2019-06-21 23:55发布

问题:

Is it safe, like in the case of std::mutex for a std::promise<T> to be made mutable, or does it depend on T? As in:

using Data = std::tuple<bool, int, int>;

struct X {

    std::future<Data> prepare() const {
        return m_promise.get_future();
    }

    void asyncHandler(int a, int b) const {
        m_promise.set_value({true, a, b});
    }

    void cancel() const {
        m_promise.set_value({false, 0, 0});
    }

    mutable std::promise<Data> m_promise;  // Is this safe?
};


void performAsyncOp(const X& x) {
     std::future<Data> fut = x.prepare();
     dispatch(x);
     std::future_status result = fut.wait_for(std::chrono::milliseconds(150));
     if (result == std::future_status::timeout) {
         x.cancel();
     }

     handleResult(fut.get());
}

回答1:

Let's have a detailed look at the API:

// retrieving the result
future<R> get_future();

// setting the result
void set_value(see below);
void set_exception(exception_ptr p);

// setting the result with deferred notification
void set_value_at_thread_exit(see below);
void set_exception_at_thread_exit(exception_ptr p);

None of the methods is marked const, so we can't infer any knowledge about the constness from just this. However, the standard mandates thread-safety on the following methods (c.f. 33.6.6.2): set_­value, set_­exception, set_­value_­at_­thread_­exit, and set_­exception_­at_­thread_­exit.

This leaves get_future unspecified with respect to thread-safety. However, get_future throws an exception if called more than once, c.f. 33.6.6.14.1. So calling get_future from multiple threads doesn't really make sense from a practical point of view.

There is no guarantee for thread-safety when calling get_future and any of the set methods and get_future (no matter if it will throw or not) simultaneously, as far as I can see.