1. 程式人生 > >多執行緒技術——windows.h【1】

多執行緒技術——windows.h【1】

執行緒的狀態

執行緒有掛起狀態、執行狀態、阻塞狀態和等待狀態。

下面分別介紹:

  • 掛起狀態:執行緒建立後並沒有直接執行或是呼叫函式掛起了執行緒。被掛起了的執行緒沒有執行的能力,只有呼叫啟動函數了之後才能執行。
  • 執行狀態:線上程的時間片內,擁有CPU資源的時候,這是,執行緒便開始執行。
  • 阻塞狀態:由於進行大量輸入輸出操作或發生執行錯誤時,執行緒失去執行狀態,只有等待問題解除之後,執行緒才能進入等待狀態。
  • 等待狀態:執行緒啟動或時間片搶佔失敗是等待其他執行緒執行,在此期間,執行緒隨時可能被執行。

多執行緒實現

執行緒核心物件就是一個包含了執行緒狀態資訊的資料結構。每次對CreateThread 的成功呼叫,系統都會在內部為其分配一個核心物件。

執行緒上下文反應了執行緒上次執行的暫存器狀態,來保證執行緒之間切換(即還原現場)。

計數器,呼叫一次OpenThread(CreateThread ),計數器加1,CloseThread(CloseHandle)計數器減一。當計數器值為0時,沒有執行緒使用該核心物件,系統收回記憶體。計數器的初始值是2(主執行緒是1,建立的執行緒是2)。

  • 標頭檔案 因為C++不像Java一樣需要進行跨平臺優化,所以我們使用最簡單的方法來實現多執行緒技術——windows.h中的CreateThread以及相關函式和類。首先,以如下的方式引用標頭檔案:
#include<windows.h>
  • 函式原型:
HANDLE  CreateThread(
   LPSECURITY_ATTRIBUTES lpThreadAttributes, //執行緒安全性描述(一個結構體,一般是NULL)
   SIZE_T dwStackSize,                      //一種數值(棧深度,一般是0)   
   LPTHREAD_START_ROUTINE lpStartAddress,  //啟動函式
   _In_opt_ __drv_aliasesMem LPVOID lpParameter, // 附加引數(一般為NULL)
    _In_ DWORD dwCreationFlags,          //執行引數(是否在建立完成後就啟動執行緒
_Out_opt_ LPDWORD lpThreadId // 返回控制代碼(一般是0,或者是一個DWORD型變數的地址,別忘了&) );
  • 引數說明 第三個引數 ——啟動函式:

    c LPTHREAD_START_ROUTINE lpStartAddress

    我們一般這樣寫: (LPTHREAD_START_ROUTINE) ThreadStart 意思就是線上程啟動的時候呼叫ThreadStart,之後他就不管了,也就是說這個函式? 就是執行緒主函式相當於main的意思。也就是說在這個函式中呼叫的類資源或函式資源 都是屬於這個執行緒的。除了static的儲存類。

    倒數第二個引數——執行引數。

    這是實際上是一個bool型別的值,用於標示是否在建立執行緒後立刻執行,如果為true,也就是0,那麼就會立刻執行,否則將會掛起,等待啟動

  • 返回值 還有我要說一下HANDLE這個型別,它其實是一個指標,也是CreateThread的返回值。也就是一個執行緒控制代碼,用於標示一個執行緒。當然,其他對於執行緒的操作都需要使用這個指標。

  • 啟動執行緒: 如果呼叫這個函式,將會啟動HANDLE引數所代表的執行緒.

    DWORD ResumeThread(HANDLE hThread); //啟動執行緒
    //說明:DWORD是一個數值,代表控制代碼,無需關注;
    //引數表示要啟動的執行緒的控制代碼,也就是剛才介紹的由CreateThread返回的HANDLE
    
  • 掛起執行緒 下面我們看看如何掛起執行緒,使執行緒進入掛起狀態:

     DWORD SuspendThread(HANDLE hThread); //掛起執行緒
    //說明:DWORD是一個整數值,代表一個控制代碼,無需過分關注
    //引數:一個HANDLE執行緒指標,由CreateThread建立
    
  • 停止執行緒 掛起執行緒後可以進行釋放以便停止執行緒:

     delete HANDLE //釋放指標資源
     //說明:HANDLE是一個HANDLE型指標,代表釋放一個執行緒的資源,使執行緒死亡
    

    實際上,停止一個執行緒還有一種方法——強行停止,但是已經不建議使用,現在都是使用掛起+delete的方法,因為使用強行停止會有很多的安全問題,但也是一個功能,所以在這裡為大家介紹一下:

    BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode); //強行停止執行緒
    //說明:返回值代表是否成功
    //引數:HANDLE指標代表需要結束的執行緒,DWORD數值代表該執行緒的退出值
    //功能:在任何位置結束任何執行緒
    
  • 等待狀態 掛起執行緒可能為了等待重要操作然後再執行執行緒,以下函式將解除執行緒掛起狀態,使執行緒進入等待狀態:

      	DWORD ResumeThread(HANDLE hThread); //使執行緒脫離掛起狀態
      	//說明:返回值也是控制代碼
      	//引數:HANDLE型別指標,表示要繼續的執行緒,或剛建立而沒有啟動的執行緒
      	//注意:如果對等待狀態下的執行緒使用本函式,可能會丟擲異常或無效果,具體請見MSDN
    
  • 簡單的例程

    //多執行緒搶佔輸出
    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    void ThreadUser() { //執行緒入口
       cout << "子執行緒開始" << endl;
       for (int i = 0; i < 10; i++) { //搶佔迴圈
       	cout << "子執行緒第" << i << "次迴圈搶佔;" << endl; //輸出資訊
       	Sleep(100); //搶佔延時
       }
       cout << "子執行緒結束" << endl;
    }
    
    int main() {
       cout << "主執行緒開始" << endl;
       HANDLE h; //執行緒控制代碼
       h=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadUser, NULL, 1, 0); //建立子執行緒
       ResumeThread(h);  //啟動子執行緒
       for (int i = 0; i < 10; i++) { //搶佔迴圈
       	cout << "主執行緒第" << i << "次迴圈搶佔;" << endl; //輸出資訊
       	Sleep(100); //搶佔延時
       }
       Sleep(1000); //等待子執行緒
       CloseHandle(h); 
       cout << "主執行緒結束" << endl;
       system("pause");
       return 0;
    }