https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60966

--- Comment #25 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Leon Timmermans from comment #24)
> > get_future() is non-const, set_value() is non-const.
> 
> I can see your point from a C++ point of view, but this doesn't make sense
> from a usable threading point of view. IMHO, the whole point of abstractions
> such as promises is to isolate the user from such issues.

Within reason yes, but not entirely. You can't expect to safely assign to the
same std::promise in two threads for example.

Anyway, that's not the real issue here, the example can be fixed to avoid such
race conditions but still demonstrate the problem:

#include <future>
#include <thread>
#include <vector>

struct DummyTask {
    DummyTask(int id) : id_(id) {}
    int id_;
    std::promise<void> pr;
};

const int THREADS = 100;

void run_task(DummyTask* task) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    task->pr.set_value();
}

void wait_for_task(std::future<void> fut) {
    fut.wait();
}

int main() {
    std::vector<const DummyTask*> tasks;
    std::vector<std::thread> threads;
    std::vector<std::future<void>> futures;
    for (int i = 0; i < THREADS; ++i) {
        DummyTask* task = new DummyTask(i);
        tasks.push_back(task);
        futures.push_back(task->pr.get_future());
        threads.emplace_back(run_task, task);
    }

    for (int i = 0; i < THREADS; ++i) {
        wait_for_task(std::move(futures[i]));
        // Because we returned from wait_for_task for this task, run_task is
surely done.
        // No one else is referring to the task. So, even before
threads[i]->join(),
        // it should be safe to delete it now.
        delete tasks[i];  // but here you get an invalid read!
    }
    for (int i = 0; i < THREADS; ++i) {
        threads[i].join();
    }
}

Reply via email to