多執行緒程式設計之建立執行緒(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執行緒庫的使用。