Windows多執行緒與執行緒繫結CPU核心
一、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()函式關閉
函式功能:讓執行緒進入等待轉態,直到條件觸發(所有執行緒執行結束)。核心物件在執行期間處於未觸發的狀態,直到執行結束。
DWORDWINAPIWaitForMultipleObjects( 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