检查线程是否完成的正确方法?

时间:2010-07-05 14:15:29

标签: c++ c windows multithreading

我正在使用_beginthread在我的应用程序中使用多线程,并且现在要等到所有线程都完成我有全局bool,当每个线程完成时设置为true,所以我在while循环之前。必须有一个更简洁的方法吗?

由于

6 个答案:

答案 0 :(得分:8)

您可以使用WaitForMultipleObjects等待线程在主线程中完成。

答案 1 :(得分:3)

您想要了解的是线程同步技术 - 幸运的是,MSDN上有相当多的信息可能会帮助您解决问题。你可能想要使用事件和WaitHandles这里是MSDN上的主要内容:http://msdn.microsoft.com/en-us/library/ms681924%28v=VS.85%29.aspx有很多例子。

MFC中还有一些关于同步的信息(可能会或可能不会有用,可供参考之用):http://msdn.microsoft.com/en-us/library/975t8ks0%28VS.71%29.aspx

我已经做了一些搜索,但是我很难找到一些不使用MFC实现的有用信息。这里有一个很好的教程(http://www.informit.com/library/content.aspx?b=Visual_C_PlusPlus&seqNum=149)但是,再次使用MFC。你可以看看MFC的互斥体实现虽然是一个开始。

因此,您需要熟悉同步功能和结构 - 所有这些都在MSDN上进行了介绍:http://msdn.microsoft.com/en-us/library/ms686679%28v=VS.85%29.aspx

答案 2 :(得分:2)

请改用_beginthreadex_beginthread_beginthreadex return a thread handle都有,但以_beginthread开头的线程会在完成时自动关闭其句柄,因此使用它进行同步是不可靠的。

线程句柄可以与Win32的某个同步函数一起使用,例如WaitForSingleObjectWaitForMultipleObjects

完成后,必须使用_beginthreadex关闭CloseHandle()返回的句柄。

答案 3 :(得分:2)

通常的方法是保留所有线程句柄,然后等待每个句柄。当句柄发出信号时,线程已完成,因此它将从线程集中删除。我使用std::set<HANDLE>来跟踪线程句柄。在Windows中等待多个对象有两种不同的方法:

  1. 对集合进行迭代,并在每个
  2. 上超时调用WaitForSingleObject
  3. 将集合转换为数组或向量,然后调用WaitForMultipleObjects
  4. 第一种听起来效率低下,但它实际上是两者中最直接且最不容易出错的。如果需要等待所有线程,请使用以下循环:

    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);
    }
    

    使用WaitForMultipleObjects等待线程完成比听起来要困难一些。以下将等待所有线程;但是,它一次只等待WAIT_MAXIMUM_OBJECTS个线程。另一个选择是遍历每个线程页面。我会把这个练习留给读者;)

    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
            }
        }
    }
    

    这不是很漂亮,但应该有效。如果您相信所有线程都会退出并且不介意等待它们,那么您可以使用WaitForMultipleObjects(ary.size(), &ary[0], TRUE, INFINITE)。这通常不是很安全,但是因为失控的线程会导致应用程序无限期阻塞只有当ary.size()小于MAXIMUM_WAIT_OBJECTS时它才会起作用。

    当然另一个选择是找到一个线程池实现并改为使用它。编写线程代码并不是很有趣,特别是一旦你必须在野外支持它。请考虑使用类似boost::thread_group的内容。

答案 4 :(得分:1)

您可以使用boost :: thread对象。在对象上调用join,它将等待线程完成。

答案 5 :(得分:0)

Windows为一个线程提供事件以通知另一个线程。开箱即用Visual C ++仅在MFC内提供对事件的支持。对于便携式非MFC版本,请检查Boost库的thread management classes。尽管它们不能直接访问所有Windows API的功能,但它们使启动和等待线程变得更加容易。