Manjunath Ballur
Manjunath Ballur

Reputation: 6343

Signalling the completion of std::async task

I have used std::async for speeding up the execution of a task, which was previously being executed sequentially.

My implementation does the following:

  1. Launches a pre-configured number of tasks (for e.g. at max 10 concurrent tasks)
  2. The futures for these tasks are stored in a vector.
  3. As soon as one task is finished, it launches another task, so that at any point of time, at max 10 tasks (this value is configured) are running.
  4. After launching 10 tasks, my implementation waits for the oldest task (i.e. the first task in the vector) to complete, by calling get() on that future.

Though this works fine, it is possible that any of the 10 tasks could complete first. My implementation always waits on the first task in the vector. Is there a way to know, which of the 10 tasks completed first?

For e.g. future object itself signalling that it is ready.

I want to achieve functionality similar to "WhenAny()" function mentioned in this article: https://msdn.microsoft.com/en-us/library/jj155756.aspx

Upvotes: 0

Views: 664

Answers (3)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275280

Use a thread pool. Queue all of your tasks. Have them report to an atomic counter when done, and have them signal a condition variable when the counter says all are done.

Thread pool implementations abound on stack overflow and elsewhere.

I find using C++11 threading primitives directly in client code is questionable; using them to write little helpers is a better idea.

Upvotes: 1

Leinadp
Leinadp

Reputation: 36

I think that the equivalent to WhenAny (C#) has not yet been incorporated in the C++11/14 standard, thought it is being considered as an experimental future extension (see this). I think latests versions of Boost libraries include when_any, check this out. This company sells also a complete thread library that includes when_any.

Upvotes: 1

Tyler
Tyler

Reputation: 1827

Give them each an ID and use an atomic to store the first that finishes.

Somewhere in scope of all of the functions:

std::atomic<int> first_id(0);

At the completion of each task:

first_id.compare_exchange_strong(0, id);

Where id is from 1 to 10. It will only run once and the first one to run this will be the one to replace the 0.

Edit: The above is the answer to your literal question. But it doesn't really help you do what you want. To do what you want, I'd change the vector to a queue and have each task enqueue the next when it exits (you'll also need a lock to lock the queue before modifying it.) Alternatively, you could use a threadpool. (Shameless plug: here's mine.) A thread pool would let you enqueue all the tasks, but only use n threads, which will prevent overtaxing the scheduler while still making the coding simple.

Upvotes: 1

Related Questions