一、Windows創建多線程的方法有CreadThread()和_beginthreadex()函數,Win32 提供了一系列的API函數來完成線程的創建、掛起、恢復、終結以及通信等工作,頭文件在
#include<windows.h>
先介紹一下CreateThread()主要的函數列表
CreateThread()函數原型
HANDLE WINAPI CreateThread( _In_opt_ LPSECURITY_ATTRIBUTES //lpThreadAttributes, 線程內核對象的安全屬性,一般傳入NULL表示使用默認設置。 _In_ SIZE_T //dwStackSize,表示線程棧空間大小。傳入0表示使用默認大小(1MB) _In_ LPTHREAD_START_ROUTINE //lpStartAddress,表示新線程所執行的線程函數地址,多個線程可以使用同一個函數地址 _In_opt_ LPVOID //lpParameter,是傳給線程函數的參數 _In_ DWORD //dwCreationFlags,指定額外的標志來控制線程的創建,為0表示線程創建之后立即就可以進行調度,如果為CREATE_SUSPENDED則表示線程創建后暫停運行,這樣它就無法調度,直到調用ResumeThread()恢復運行 _Out_opt_ LPDWORD //lpThreadId將返回線程的ID號,傳入NULL表示不需要返回該線程ID號 );
CreateThread()函數的返回值
線程創建成功返回新線程的句柄,失敗返回NULL
線程等待函數(關閉線程)
CreateThread()創建的函數不會隨着程序結束自動關閉,需要自己調用WaitForMultipleObjects()函數關閉
函數功能:讓線程進入等待轉態,直到條件觸發(所有線程執行結束)。內核對象在運行期間處於未觸發的狀態,直到執行結束。
DWORD WINAPI WaitForMultipleObjects( DWORD nCount, //CPU內核對象的個數 CONST HANDLE *lpHandles, //句柄數組的地址 BOOL bWaitAll, //是否等待所有線程結束 DWORD dwMilliseconds //等待的最大時間,單位毫秒,INFINITE表示無限等待 );
二、_beginthreadex()函數的參數和CreateThread()函數一樣,都是六個,_beginthreadex()是C/C++語言另有一個創建線程的函數,我們應該盡量使用_beginthreadex()來代替使用CreateThread(),因為它比CreateThread()更安全。
_beginthreadex創建的每個線程都將擁有自己專用的一塊內存區域來供標准C運行庫中所有有需要的函數使用。而且這塊內存區域的創建就是由C/C++運行庫函數_beginthreadex()來負責的。這塊區域可以用來存放一些線程獨享的數據,不會被其它線程修改,所以更安全。
三、多線程綁定CPU內核
在線程數和CPU內核數大致相等的情況下,將線程與CPU內核綁定,可以減少線程的上下文切換帶來的開銷,提高CPU Cache緩存的命中率,提高運行效率
Windows是使用SetThreadAffinityMask(handle[i], 1 << i);函數來將線程與CPU內核綁定的,第一個參數handle[ i ] 是線程的句柄,第二個參數代表CPU核心的編號
SetThreadAffinityMask()函數的返回非零值表示綁定CPU內核成功,為零值表示失敗
線程的句柄可以通過CreateThread()創建線程的返回值獲取,也可以使用GetCurrentThread()函數的返回值獲取當前執行線程的句柄
注意CPU的內核編號是按照二進制位來表示的,每個二進制位指向一個內核
比如對4核的CPU
第一個核編號是0x0001
第二個核編號是0x0010
第三個核編號是0x0100
第四個核編號是0x1000
#include<process.h> #include<windows.h> #include<thread> #include<iostream> using namespace std; //CreateThread()核_beginthreadex()的線程函數要求是全局變量的一個函數 unsigned int __stdcall ThreadFun(PVOID pM) { printf("線程ID 為 %d 的子線程輸出: Hello World\n", GetCurrentThreadId()); while (1) { } return 0; } int main() { //獲取CPU核心數目 int x = thread::hardware_concurrency(); const int THREAD_NUM = 4; HANDLE handle[THREAD_NUM]; unsigned long mask; for (int i = 0; i < THREAD_NUM; i++) { //CREATE_SUSPENDED創建線程之后掛起 handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, CREATE_SUSPENDED, NULL); //mask值為0表示設置失敗,非零值表示成功 mask=SetThreadAffinityMask(handle[i], 1 << i); if(mask==0) printf("ERROR\n"); } int n, t = 4; while (t--) { cin >> n; //喚醒句柄為handle[n]的線程 ResumeThread(handle[n]); } //等待所有線程退出 WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE); system("pause"); return 0; }
喚醒線程運行之前CPU使用狀況
喚醒句柄為0的線程運行
喚醒句柄為1的線程運行
喚醒句柄為3的線程運行
喚醒句柄為2的線程運行
參考博客
https://www.cnblogs.com/ay-a/p/8762951.html
https://blog.csdn.net/zhangxiangdavaid/article/details/43700485