2010-07-05 41 views
5

我正在使用_beginthread在我的應用程序中使用多線程,現在要等到所有線程都完成我有全局布爾值在每個線程完成時都設置爲true,所以我在while循環中,直到那時。必須有更乾淨的方式來做到這一點?檢查線程是否完成的正確方法?

感謝

回答

8

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

+0

如果您只有一個線程ID,您需要先調用[OpenThread](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684335(v = vs)來將其轉換爲HANDLE 0.85)的.aspx)。 – rustyx 2016-01-10 20:29:48

+2

不,請不要撥打OpenThread!如果線程已經退出並且ID已被重新分配,則最終可能會有一個句柄指向另一個隨機線程。使用_beginthreadex,它返回線程的句柄。 (_beginthread也返回一個句柄,但是(引用文檔)它「可能是無效的或者指向另一個線程」。不要使用_beginthread。) – benrg 2016-03-19 05:39:27

3

你想看看是線程同步技術是什麼 - 幸運的是MSDN上相當多的信息,這可能可以幫助你。這很可能是您想要使用Events和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

+0

你肯定需要使用布爾事件。 – DanDan 2010-07-05 14:27:04

2

改爲使用_beginthreadex_beginthread_beginthreadexreturn a thread handle,但以_beginthread開頭的線程在完成時自動關閉其句柄,因此將其用於同步不可靠。

線程句柄可以與Win32的同步函數之一一起使用,例如WaitForSingleObjectWaitForMultipleObjects

完成後,由_beginthreadex返回的句柄必須用CloseHandle()關閉。

0

Windows爲一個線程提供事件以通知另一個線程。開箱即用的Visual C++僅支持MFC內部的事件。對於便攜式非MFC版本,請檢查Boost庫的thread management classes。它們使啓動和等待線程變得更容易,但它們不能直接訪問所有Windows API的功能。

1

通常的方法是保留所有線程句柄,然後等待每個句柄。當句柄爲的信號爲時,該線程已完成,因此將其從該組線程中移除。我使用std::set<HANDLE>來跟蹤線程句柄。存在用於在Windows等待多個對象上兩種不同的方法:

  1. 遍歷所述組並調用WaitForSingleObject與每一個
  2. 超時轉換集合到一個數組或載體和呼叫WaitForMultipleObjects

第一種聽起來效率低下,但它實際上是兩者中最直接和最不容易出錯的。如果您需要等待所有線程,然後用下面的循環:

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的東西。

0

你可以使用boost :: thread對象。在對象上調用join,它將等待線程完成。

相關問題