Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WaitForMultipleObjects alternative with std::thread?

My problem is that I have multiple threads, they are stored in some container, and I need to know when a thread at a certain position finished. On windows I would do something like:

HANDLE handles[3];
//handles were initialized
DWORD finishingThread = WaitForMultipleObjects(3, handles, false, INFINITE)

Is there any way to achieve the same effect with std::thread?

like image 319
Moshe Magnes Avatar asked Jan 31 '14 08:01

Moshe Magnes


4 Answers

To the very best of my knowledge, there is nothing in the standard library that supports a wait of that nature. The standard library is built on top of the underlying operating system threading support. By necessity the standard library can only offer lowest common denominator functionality. Which means that it is not able to wrap some of the richer functionality offered by the Win32 threading library.

like image 194
David Heffernan Avatar answered Oct 21 '22 10:10

David Heffernan


Just use a std::condition_variable and have your threads fire notify_all() or notify_one() right before they finish.

Then do cv.wait() where you want your WaitForMultipleObjects() call.

like image 38
Nick Strupat Avatar answered Oct 21 '22 08:10

Nick Strupat


Try Async++ Composition which is a reference implementation for the N3428 C++ standard proposal.

This article is relevant before that:

Broken promises–C++0x futures

In an unportable way you can also call std::thread::native_handle() to use WaitForMultipleObjects with the return.

like image 1
pepper_chico Avatar answered Oct 21 '22 08:10

pepper_chico


Here's an example of how you can achieve the same effect using std::thread and std::future if you are willing to let the main thread sleep while polling the readiness of the threads (alternatively you could let a dedicated thread handle the waiting).

Consider this function, taking a range of iterators to a container of std::future, which will block until at least one task is finished:

const int TIME_BETWEEN_POLLS_MS = 50;

// Wait (sleep) between polls until a task is finished then return iterator to future.
template <typename Iterator>
Iterator waitForFirst(Iterator first, Iterator last) {
    auto it = first;
    auto status = std::future_status::timeout;
    while (status != std::future_status::ready) {
        if (++it == last) { // Rotate in range.
            it = first;
        }
        status = it->wait_for(std::chrono::milliseconds(TIME_BETWEEN_POLLS_MS));
    }
    return it;
}

Now if you have a container of futures (std::future) associated with the return values of your tasks running on separate threads, you can simply use the function waitForFirst to get an iterator to the future that gets its result first.

    // Lets say you have a vector of futures, e.g.
    std::vector<std::future<std::thread::id>> futures;

    /* Push futures to vector... */

    // Block until first task is finished.
    // 'it' is iterator to future associated with result.
    auto it = waitForFirst(std::begin(futures), std::end(futures));

See live example

like image 1
Felix Glas Avatar answered Oct 21 '22 08:10

Felix Glas