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();
}
}