1. 程式人生 > >windows下繫結執行緒(程序)到指定CPU

windows下繫結執行緒(程序)到指定CPU

不知各位程式設計師在測試程式碼效能的時候有沒有注意過,一個程式指定到單獨一個CPU上執行會比不指定CPU執行時快。這中間主要有兩個原因:
1)CPU切換時損耗的效能。
2)Intel的自動降頻技術和windows的機制衝突:windows有一個功能是平衡負載,可以將一個執行緒在不同時間分配到不同CPU,從而使得每一個CPU不“過累”。然而,Inter又有一個技術叫做SpeedStep,當一個CPU沒有滿負荷執行時自動降頻從而達到節能減排的目的。這兩個功能實際是衝突的:一個程式被分配到多個CPU協同工作->每個CPU都不是滿載->每個CPU都會降頻->windows發現每個CPU效能都降低了,因此程式執行速度也降低了。

因此,將執行緒(程序)繫結到指定CPU核心,從而不讓windows自作主張幫我們分散任務,從而提高單執行緒效率是很有必要的。有兩種方法實現繫結程序到指定CPU:
1)手工調節:在資源管理器的程序裡面,設定相關性,可以設定程序到某個或者某些指定的CPU核心。
手工指定CPU核心
這種方法最簡便,同樣是最優效率的,因為你可以根據當前CPU的負載情況進行選擇。
2)程式碼自動調節:
參考:http://www.cnblogs.com/kex1n/archive/2011/05/09/2040924.html
具體函式為:

1
DWORD_PTR SetThreadAffinityMask(HANDLE hThread, DWORD_PTR dwThreadAffinityMask);

其中,第一個引數為執行緒控制代碼,第二個引數為一個mask。
如果要知道當前執行緒的控制代碼,可以通過函式:GetCurrentThread()得到。否則,在建立多執行緒的時候,也同樣可以得到建立的執行緒的控制代碼。
第二個引數為mask,可取值為0~2^31(32位)和0~2^63(64位),每一位代表每一個CPU是否使用。
比如,你要指定程序到第0個CPU上,則mask=0×01
第1個CPU:mask=0×02
第2個CPU:mask=0×04 (注意不是0×03)
第3個CPU:mask=0×08
以此類推。
如果要指定多個CPU:
比如第0、1個:mask=0×03
第1、2個:mask=0×06
以此類推。
如果CPU個數不足,則會進行取模操作。比如一共4個CPU,則mask=0×0010則和0×01一樣。
這種方法的好處是多執行緒時不用每次都手動選擇CPU,缺點是萬一選到的CPU負載很高,那麼程式執行速度就慢了(英雄所見略同所以大家都搶到同一個CPU去了麼~~)
效果如下圖所示:

指定CPU核心
還有一個實用的函式來獲取當前CPU的核心數量:

1
2
3
SYSTEM_INFO info;
GetSystemInfo(&info);
printf("Number of processors: %d.\n", info.dwNumberOfProcessors);

輸出的是邏輯核心數量,比如i3處理器就是雙核心四執行緒,輸出4。i5處理器是四核心四執行緒,輸出也是4。
這樣就可以方便的知道當前系統一共有多少個CPU了,同時也方便了執行緒數選擇。