views:

169

answers:

6

I'm using multithreading in my application with _beginthread and right now to wait until all threads are done I have global bools that get set to true as each thread completes so I'm in a while loop until then. There must be a cleaner way of doing this?

Thanks

+3  A: 

What you want to have a look at is thread synchronization techniques - luckily there is quite a bit of information on MSDN which can probably help you out. It's likely you'll want to use Events and WaitHandles here's the main stuff on MSDN: http://msdn.microsoft.com/en-us/library/ms681924%28v=VS.85%29.aspx there are a number of examples.

There's also some info on synchronization in MFC (which may or may not prove helpful, added for reference purposes): http://msdn.microsoft.com/en-us/library/975t8ks0%28VS.71%29.aspx

I've done a bit of searching, but I've had a hard time trying to track down some helpful info for you which doesn't use the MFC implementation. There's a good tutorial here ( http://www.informit.com/library/content.aspx?b=Visual_C_PlusPlus&seqNum=149 ) but, again, using MFC. You could take a look at the MFC implementation of mutexes though as a start.

So, you'd need to get familiar with synchronization functions and structures - all covered here on MSDN: http://msdn.microsoft.com/en-us/library/ms686679%28v=VS.85%29.aspx

RobS
You definitely need to be using events over bools.
DanDan
+6  A: 

You can use WaitForMultipleObjects to wait for the threads to finish in primary thread.

Dave18
+2  A: 

Use _beginthreadex instead. Both _beginthread and _beginthreadex return a thread handle, but the thread started with _beginthread automatically closes its handle when it finishes, so using it for synchronization is not reliable.

Thread handle can be used with one of the synchronization functions of Win32, such as WaitForSingleObject or WaitForMultipleObjects.

When done, handles returned by _beginthreadex must be closed with CloseHandle().

atzz
A: 

Windows provides events for one thread to notify another. Out of the box Visual C++ provides support for events only inside MFC. For a portable, non-MFC version, check the thread management classes of the Boost library. They make launching and waiting for threads a lot easier, although they don't provide direct access to all of Windows API's functionality.

Panagiotis Kanavos
A: 

The usual method is to keep all of the thread handles and then wait on each handle. When the handle is signaled, the thread has finished so it is removed from the set of threads. I use std::set<HANDLE> to keep track of the thread handles. There are two different methods for waiting on multiple objects in Windows:

  1. Iterate over the set and call WaitForSingleObject with a timeout on each one
  2. Convert the set into an array or vector and call WaitForMultipleObjects

The first sounds inefficient, but it is actually the most direct and least error prone of the two. If you need to wait for all of the threads, then use the following loop:

std::set<HANDLE> thread_handles; // contains the handle of each worker thread
while (!thread_handles.empty()) {
    std::set<HANDLE> threads_left;
    for (std::set<HANDLE>::iterator cur_thread=thread_handles.begin(),
                                    last=thread_handles.end();
         cur_thread != last; ++cur_thread)
    {
        DWORD rc = ::WaitForSingleObject(*cur_thread, some_timeout);
        if (rc == WAIT_OBJECT_0) {
            ::CloseHandle(*cur_thread); // necessary with _beginthreadex
        } else if (rc == WAIT_TIMEOUT) {
            threads_left.add(cur_thread); // wait again
        } else {
            // this shouldn't happen... try to close the handle and hope
            // for the best!
            ::CloseHandle(*cur_thread); // necessary with _beginthreadex
        }
    }
    std::swap(threads_left, thread_handles);
}

Using WaitForMultipleObjects to wait for the threads to finish is a bit more difficult than it sounds. The following will wait for all of the threads; however, it only waits for WAIT_MAXIMUM_OBJECTS threads at a time. Another options is to loop over each page of threads. I'll leave that exercise to the reader ;)

DWORD large_timeout = (5 * 60 * 1000); // five minutes
std::set<HANDLE> thread_handles; // contains the handle of each worker thread
std::vector<HANDLE> ary;         // WaitForMultipleObjects wants an array...
while (!thread_handles.empty()) {
    ary.assign(thread_handles.begin(), thread_handles.end());
    DWORD rc = ::WaitForMultipleObjects(std::min(ary.size(), WAIT_MAXIMUM_OBJECTS),
                                        &ary[0], FALSE, large_timeout);
    if (rc == WAIT_FAILED) {
        // handle a failure case... this is usually something pretty bad
        break;
    } else if (rc == WAIT_TIMEOUT) {
        // no thread exited in five minutes... this can be tricky since one of
        // the threads beyond the first WAIT_MAXIMUM_OBJECTS may have terminated
    } else {
        long idx = (rc - WAIT_OBJECT_0);
        if (idx > 0 && idx < ary.size()) {
            // the object at `idx` was signaled, this means that the
            // thread has terminated.
            thread_handles.erase(ary[idx]);
            ::CloseHandle(ary[idx]); // necessary with _beginthreadex
        }
    }
}

This isn't exactly pretty but it should work. If you trust that all of your threads will exit and don't mind waiting for them, then you can use WaitForMultipleObjects(ary.size(), &ary[0], TRUE, INFINITE). This usually isn't very safe though since a runaway thread will cause your application to block indefinitely and it will only work if ary.size() is less than MAXIMUM_WAIT_OBJECTS.

Of course the other option is to find a thread pool implementation and use it instead. Writing threading code is not really a lot of fun especially once you have to support it in the wild. Consider using something like boost::thread_group instead.

D.Shawley
A: 

You can use boost::thread objects. Call join on the object and it will wait for the thread to finish.

Duracell