mhbackes
mhbackes

Reputation: 96

std::async/std::future timeout with partial results

I would like to run a function with a timeout. And if the timeout is reached I would like to have access to the partial result generated by the thread before the timeout happened.

As an example, I would like to do something similar to this in c++17:

std::vector<int> my_result;

auto future = std::async(std::launch::async, [&my_result]() {
    for (int i = 0; i < 100000; i++)
      my_result.push_back(i);
});

auto status = future.wait_for(std::chrono::milliseconds(1));
if (status == std::future_status::timeout) {
    std::cout << "Partial result:" << std::endl;
    for (auto i : my_result)
       std::cout << i << std::endl;
}

Is is safe to do something like this? Is there a guarantee if the timeout happens during the call to push_back() the vector will not be left in an inconsistent state?

If not, is there a better way to do this?

Upvotes: 1

Views: 255

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 473437

It is absolutely not safe. A timeout occurs when the process being waited on has not completed. future is purely binary synchronization; either the process is complete and the result object (and any side effects) are available to the receiving thread, or the process is not complete and nothing is synchronized to the receiving thread. Therefore, attempting to access my_result from the receiving thread without synchronizing with the sending thread results in undefined behavior.

If you want to have partial results, then there must be synchronization between the source and the destination of those partial results. The sender has to decide how many results to expose, and once exposed, the sender cannot do anything to any of the objects in the exposed partial results. Any new results either go into a different object or into an object that handles the synchronization hand-off between source and destination. Likewise, the receiver has to be able to test for when the partial results are ready and extract them.

future is not the API for something like that. You basically need some kind of work queue-style interface, and both threads have to be specially coded to handle it.

Upvotes: 3

Related Questions