0

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

Manjunath Ballur
  • 6,287
  • 3
  • 37
  • 48
  • Maybe a dupe: http://stackoverflow.com/questions/27341029/what-is-the-best-way-to-wait-on-multiple-condition-variables-in-c11 – Mooing Duck Apr 15 '16 at 20:21
  • Show some code. There are a lot of ways to do this. – Tyler Apr 15 '16 at 20:31
  • Thanks for the answer. I'll add more details to the question. – Manjunath Ballur Apr 15 '16 at 20:32
  • 1
    For example, you could manually have a callback at completion. If the "next task function" needs information that is only available in the scope of the function that originally created the tasks, you could write the callback as a lambda. – Tyler Apr 15 '16 at 20:32
  • The task will take a callback. The callback will have logic to update a shared state, which will indicate which of the tasks have completed. After completion, each task calls the callback, which updates the state for the completed task. So, when the launcher has to launch a new task, it will immediately know from the shared state, which of the 10 tasks has completed. – Manjunath Ballur Apr 15 '16 at 20:43
  • 1
    Is there any reason the callback couldn't launch the next task itself? That would be simpler. Of course, there could be extra constraints I don't know about preventing it. – Tyler Apr 15 '16 at 20:59

3 Answers3

1

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.

Tyler
  • 1,818
  • 2
  • 13
  • 22
1

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.

Leinadp
  • 36
  • 1
1

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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524