windows編程 使用C++實現多線程類

來源:互聯網
上載者:User

標籤:csdn   win   plain   弱類型   lan   類型   設定   mil   windows編程   

有時候我們想在一個類中實現多線程,主線程在某些時刻獲得資料,可以“通知”子線程去處理,然後把結果返回。下面的執行個體是主線程每隔2s產生10個隨機數,將這10隨機數傳給多線程類,讓它接收到資料後馬上列印出來。

 

首先看類的定義:

 

[cpp] view plain copy 
  1. #pragma once  
  2. #include <iostream>  
  3. #include <atlbase.h>    // 使用到了atl類  
  4. #include <atlsync.h>  
  5. #include <vector>  
  6. using namespace std;  
  7.   
  8. class CMultiThreadTest  
  9. {  
  10. public:  
  11.     bool Init();    // 初始化類成員  
  12.     bool UnInit();  // 釋放資源  
  13.     void NotifyDowork(const std::vector<int> &data);  
  14.   
  15.     static DWORD CALLBACK TestThread(LPVOID);   // 線程函數,必須是靜態函數  
  16.     DWORD TestProc();                           // 線程工作實現  
  17.   
  18. private:  
  19.     std::vector<int> m_data;    // 同步資料  
  20.     ATL::CEvent m_NotifyEvent;  // 通知事件  
  21.     HANDLE m_hThread;           // 線程控制代碼  
  22. };  


類中使用到了ALT類,需要包含atlbase.h和altsync.h標頭檔。函數TestThread必須是靜態函數,因為CreateThread只接受全域或者靜態函數。
首先先看Init()和UnInit()函數的實現:

 

 

[cpp] view plain copy 
  1. bool CMultiThreadTest::Init()  
  2. {  
  3.     // 建立事件  
  4.     BOOL bRet = m_NotifyEvent.Create(NULL, TRUE, FALSE, NULL);  
  5.     if (!bRet) {  
  6.         return false;  
  7.     }  
  8.   
  9.     // 掛起的方式建立線程  
  10.     m_hThread = CreateThread(NULL, 0, &CMultiThreadTest::TestThread, this, CREATE_SUSPENDED, NULL);  
  11.     if (NULL == m_hThread) {  
  12.         return false;  
  13.     }  
  14.   
  15.     // 喚醒線程  
  16.     ResumeThread(m_hThread);  
  17.     return true;  
  18. }  
  19.   
  20.   
  21. bool CMultiThreadTest::UnInit()  
  22. {  
  23.     // 通知線程處理data的資料  
  24.     if (m_NotifyEvent != NULL) {  
  25.         m_NotifyEvent.Set();  
  26.     }  
  27.   
  28.     if (m_hThread != NULL)   
  29.     {  
  30.         // 預留100ms讓線程處理完資料,100ms是個估值  
  31.         WaitForSingleObject(m_hThread, 100);  
  32.         CloseHandle(m_hThread);  
  33.         m_hThread = NULL;  
  34.     }  
  35.   
  36.     return true;  
  37. }  


ATL::CEvent的成員函數Create接收4個參數,第四個參數指定Event的名字(它是可以有名字的),以便在其他進程可以找到該事件,這裡我們不需要使用,把它設定為NULL,其他參數很容易理解,不贅述。
Init()函數值得注意的是我們建立的線程是以掛起的方式建立,所以必須調用ResumeThread喚醒線程,否則線程一值處於沉睡狀態,不執行線程函數。
UnInit()函數比較簡單,主要通知線程執行收尾工作,並釋放類的資源。

下面我們來看看剩下的函數的實現。

 

 

[cpp] view plain copy 
  1. DWORD CALLBACK CMultiThreadTest::TestThread(LPVOID lpParam)  
  2. {  
  3.     if (lpParam == NULL) {  
  4.         return 0;  
  5.     }  
  6.   
  7.     CMultiThreadTest *lpThis = reinterpret_cast<CMultiThreadTest *>(lpParam);  
  8.     return lpThis->TestProc();  
  9. }  
  10.   
  11.   
  12. DWORD CMultiThreadTest::TestProc()  
  13. {  
  14.     while (true)  
  15.     {  
  16.         // 每5s監聽一次,秒數直接影響程式的效能  
  17.         DWORD dwRet = WaitForSingleObject(m_NotifyEvent, 5000);  
  18.   
  19.         // 進入迴圈5s沒有事件發生,不做任何處理  
  20.         if (dwRet == WAIT_TIMEOUT) {  
  21.             continue;  
  22.         }  
  23.   
  24.     // 列印數組  
  25.         for (unsigned int i = 0; i < m_data.size(); i++)  
  26.         {  
  27.             cout <<m_data[i] <<" ";  
  28.         }  
  29.   
  30.         cout <<endl;  
  31.   
  32.         // 重設事件  
  33.         m_NotifyEvent.Reset();  
  34.     }  
  35.     return 0;  
  36. }  
  37.   
  38.   
  39. void CMultiThreadTest::NotifyDowork(const std::vector<int> &data)  
  40. {  
  41.     m_data = data;  
  42.     m_NotifyEvent.Set();    // 通知線程該做事情了!  
  43. }  


首先我們看TestThread函數,它是線程的“入口“,線程被喚醒後執行該函數。值得注意的是,我們在建立線程的時候把對象指標this作為參數傳遞給建立線程函數,系統在調用TestThread的時候會把this傳遞迴來,這裡使用弱類型轉換reinterpret_cast將LPVOID轉化為CMultiThreadTest類的指標,reinterpret_cast是一個危險的類型轉換,一般只適用於指標和整數之間的轉換。有興趣的同學可以參考C++ Primer第4版18.2.1章節。

 


線程函數將參數lpParam轉化為對象指標後,執行對象的成員函數TestProc(),TestProc()實現主要的邏輯。這裡可能會有人疑問,為什麼不直接在TestThread()函數實現主要邏輯呢?這樣做有兩個好處,一是能夠將線程函數邏輯和商務邏輯分離,其二就是TestThread是個靜態函數,類靜態函數只能處理類的靜態成員變數,而很多時候我們希望線程處理類的非靜態成員變數。
最後NotifyDowork函數很簡單,該函數給外部調用,它把外部傳進來的data賦值給類的非靜態成員變數m_data,並通知線程處理m_data資料,TestProc中WaitForSingleObject函數接收到事件後往下執行,把m_data列印出來。

下面我們看看main函數的實現:

 

[cpp] view plain copy 
  1. int _tmain(int argc, _TCHAR* argv[])  
  2. {  
  3.     CMultiThreadTest multiThreadTest;  
  4.       
  5.     // 初始化失敗  
  6.     if (!multiThreadTest.Init()) {  
  7.         return 0;  
  8.     }  
  9.   
  10.     srand(unsigned int(time(NULL)));  
  11.     std::vector<int> data;  
  12.   
  13.     while (true)  
  14.     {  
  15.         data.clear();  
  16.   
  17.         // 產生10個隨機數  
  18.         for (int i = 0; i < 10; i++)  
  19.             data.push_back(rand() % 1000);  
  20.   
  21.         // 通知多線程類執行工作  
  22.         multiThreadTest.NotifyDowork(data);  
  23.   
  24.         Sleep(2000);  
  25.     }  
  26.   
  27.     multiThreadTest.UnInit();  
  28.     return 0;  
  29. }  


這段代碼就不用解釋了,記得包含標頭檔windows.h、time.h和vector。

總結:
多線程類的使用情境是,當一個線程或得到資料後,希望其他線程能夠處理這部分數。多線程類實現還是比較簡單的,首先建立線程和線程事件,實現給外部調用的介面,外部通過介面設定事件,通知線程執行。

 

 

windows編程 使用C++實現多線程類

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.