1. 程式人生 > >多執行緒程式設計之建立執行緒(Windows下C++實現)

多執行緒程式設計之建立執行緒(Windows下C++實現)

執行緒概述

理解Windows核心物件

執行緒是系統核心物件之一。在學習執行緒之前,應先了解一下核心物件。核心物件是系統核心分配的一個記憶體塊,該記憶體塊描述的是一個數據結構,其成員負責維護物件的各種資訊。核心物件的資料只能由系統核心來訪問,應用程式無法在記憶體中找到這些資料結構並直接改變他們的內容。

常用的系統核心物件有事件物件、檔案物件、作業物件、互斥物件、管道物件、程序物件和執行緒物件等。不同型別的核心物件,其資料結構各有不同。

理解程序和執行緒

程序被認為是一個正在執行的程式的例項,它也屬於系統核心物件。可以將程序簡單的理解為一個容器,它只是提供空間,執行程式的程式碼是由執行緒來實現的。執行緒存在於程序中,它負責執行程序地址空間中的程式碼。當一個程序建立時,系統會自動為其建立一個執行緒,該執行緒被稱為主執行緒。在主執行緒中使用者可以通過程式碼建立其他執行緒,當程序中的主執行緒結束時,程序也就結束了。

執行緒的建立

Windows下,建立執行緒有多種方式,以下將逐一介紹。注意它們的區別。

使用CreateThread函式建立執行緒

Windows API函式。該函式在主執行緒的基礎上建立一個新執行緒。微軟在Windows API中提供了建立新的執行緒的函式CreateThread。

HANDLECreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//執行緒安全屬性
DWORD dwStackSize,//堆疊大小
LPTHREAD_START_ROUTINE lpStartAddress,//執行緒函式
LPVOID lpParameter,//執行緒引數
DWORD dwCreationFlags,//執行緒建立屬性 LPDWORD lpThreadId//執行緒ID );

程式碼示例如下:

#include "stdafx.h"
#include<iostream>
#include<Windows.h>
using namespace std;

DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
    cout << "thread function Fun1Proc!\n";

    return 0;
}

int main()
{
    HANDLE hThread1 = CreateThread(NULL, 0
, Fun1Proc, NULL, 0, NULL); CloseHandle(hThread1); Sleep(1000); cout << "main end!\n"; system("pause"); return 0; }

執行結果:
這裡寫圖片描述

使用_beginthreadex函式建立執行緒

除了使用CreateThread API函式建立執行緒外,還可以用C++語言提供的_beginthreadex函式來建立執行緒。

uintptr_t _beginthreadex( // NATIVE CODE  
   void *security,  //執行緒安全屬性
   unsigned stack_size,  //執行緒的棧大小
   unsigned ( *start_address )( void * ),//執行緒函式  
   void *arglist,  //傳遞到執行緒函式中的引數
   unsigned initflag,  //執行緒初始化標記
   unsigned *thrdaddr   //執行緒ID
); 

程式碼示例:

#include "stdafx.h"
#include<iostream>
#include<Windows.h>
#include<process.h>
using namespace std;

unsigned int _stdcall ThreadProc(LPVOID lpParameter)
{
    cout << "thread function ThreadProc!\n";
    return 0;
}

int main()
{
    _beginthreadex(NULL, 0, ThreadProc, 0, 0, NULL);

    Sleep(1000);
    cout << "main end!\n";
    system("pause");
    return 0;
}

使用AfxBeginThread函式建立執行緒

在MFC應用程式中,還可以使用AfxBeginThread函式建立一個執行緒。MFC提供了兩個過載版的AfxBeginThread,一個用於使用者介面執行緒,另一個用於工作者執行緒。這裡只講工作者執行緒。

CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,
  LPVOID lParam,
  int nPriority = THREAD_PRIORITY_NORMAL,
  UINT nStackSize = 0,
  DWORD dwCreateFlags = 0,
  LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
  );//用於建立工作者執行緒

返回值: 成功時返回一個指向新執行緒的執行緒物件的指標,否則NULL。
pfnThreadProc : 執行緒的入口函式,宣告一定要如下: UINT MyThreadFunction(LPVOID pParam),不能設定為NULL;
pParam : 傳遞入執行緒的引數,注意它的型別為:LPVOID,所以我們可以傳遞一個結構體入執行緒.
nPriority : 執行緒的優先順序,一般設定為 0 .讓它和主執行緒具有共同的優先順序.
nStackSize : 指定新建立的執行緒的棧的大小.如果為 0,新建立的執行緒具有和主執行緒一樣的大小的棧
dwCreateFlags : 指定建立執行緒以後,執行緒有怎麼樣的標誌.可以指定兩個值:

  • CREATE_SUSPENDED : 執行緒建立以後,會處於掛起狀態,直到呼叫ResumeThread
  • 0 : 建立執行緒後就開始執行。

lpSecurityAttrs : 指向一個 SECURITY_ATTRIBUTES 的結構體,用它來標誌新建立執行緒的安全性。如果為 NULL,那麼新建立的執行緒就具有和主執行緒一樣的安全性。

程式碼略。

其他方式

建立執行緒還可以用boost執行緒庫建立,也可以用c++11新標準中的執行緒庫(std::thread)建立執行緒。建議採用c++11中的執行緒庫建立執行緒,極為方便。且跨平臺,是語言層面的。後面會學習到c++11執行緒庫的使用。