本文整合了網上關於這塊講解比較詳細的文章,轉載者請註明!
本文參照1:http://topic.okbase.net/201010/2010101414/3909990.html
本文參照2:http://blog.csdn.net/zfive5/article/details/1499378
實現方法
進程與指定cpu綁定:SetProcessAffinityMask(GetCurrentProcess(), dwMask);
線程與指定cpu綁定:SetThreadAffinityMask(GetCurrentThread(),dwMask);
dwMask爲CPU序號的或運算值:1(0001)代表只運行在CPU1,2(0010)代表只運行在CPU2,3(0011)代表可以運行在CPU1和CPU2,以此類推。
設置之前最好判斷一下系統有幾個CPU:
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
CPU個數:SystemInfo.dwNumberOfProcessors
當前啓用的CPU序號:SystemInfo.dwActiveProcessorMask,Mask representing the set of processors configured into the system. Bit 0 is processor 0; bit 31 is processor 31.
CPU親緣性介紹
按照默認設置,當系統將線程分配給處理器時,Windows使用軟親緣性來進行操作。這意味着如果所有其他因素相同的話,它將設法在它上次運行的那個處理器上運行線程。讓線程留在單個處理器上,有助於重複使用仍然在處理器的內存高速緩存中的數據。
有一種新的計算機結構,稱爲NUMA(非統一內存訪問),在該結構中,計算機包含若干塊插件板,每個插 件板上有4個CPU和它自己的內存區。當CPU訪問的內存是它自己的插件板上的內存時,NUMA系統運行的性能最好。如果CPU需要訪問位於另一個插件板上的內 存時,就會產生巨大的性能降低。在這樣的環境中,就需要限制來自一個進程中的線程在共享同一個插件版的CPU上運行。爲了適應這種計算機結構的需要,Windows允許你設置進程和線程的親緣性。換句話說,你可以控制哪個CPU能夠運行某些線程。這稱爲硬親緣性。請注意,子進程可以繼承進程的親緣性。
注意:
(1)無論計算機中實際擁有多少個CPU,Windows98及以前系統只使用一個CPU,上述API不被支持。
(2)在大多數環境中,改變線程的親緣性就會影響調度程序有效地在 各個CPU之間移植線程的能力,而這種能力可以最有效地使用CPU時間。應用場景舉例:
將UI線程限制在一個CPU,將其他實時性要求較高的線程限制在另一個CPU。這樣,當UI需要佔用大量CPU時間時,就不會拖累其他實時性要求較高的線程的執行。同樣可以將UI線程與一些優先級不高但耗時的異步運算線程設置在不同CPU上,避免UI給人卡頓的感覺。
附錄:
SetThreadIdealProcessor(GetCurrentThread(),real_CPU_NUM);
SetThreadAffinityMask(GetCurrentThread(),real_CPU_NUM);
real_CPU_NUM爲下面的DWORD值,在msdn上面查的
0x0001 1
0x0002 2
0x0003 1 or 2
0x0004 3
0x0005 1 or 3
0x0007 1, 2, or 3
0x000F 1, 2, 3, or 4
0x0001 00000000 00000001 1
0x0003 00000000 00000011 1 and 2
0x0007 00000000 00000111 1, 2 and 3
0x0009 00000000 00001001 1 and 4
0x007F 00000000 01111111 1, 2, 3, 4, 5, 6 and 7
實例1:
//get system info
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
printf(" "
"dwNumberOfProcessors=%u, dwActiveProcessorMask=%u, wProcessorLevel=%u, "
"wProcessorArchitecture=%u, dwPageSize=%u ",
SystemInfo.dwNumberOfProcessors, SystemInfo.dwActiveProcessorMask, SystemInfo.wProcessorLevel,
SystemInfo.wProcessorArchitecture,SystemInfo.dwPageSize
);
if(SystemInfo.dwNumberOfProcessors <= 1) return;
DWORD dwMask = 0x0000;
DWORD dwtmp = 0x0001;
int nProcessorNum = 0;
for(int i = 0; i < 32; i++)
{
if(SystemInfo.dwActiveProcessorMask & dwtmp)
{
nProcessorNum++;
if(nProcessorNum <= 2)
{
//如果系統中有多個處理器,則選擇第二個處理器
dwMask = dwtmp;
}
else
{
break;
}
}
dwtmp *= 2;
}//end of for
//進程與指定cpu綁定
SetProcessAffinityMask(GetCurrentProcess(), dwMask);
//線程與指定cpu綁定
//SetThreadAffinityMask(GetCurrentThread(),dwMask);
return ;
實例2:
一個典型的應用:
將界面的線程限制在一個cpu,將其他實時性要求較高的線程限制在另一個cpu,這樣,當界面需要佔用大量cpu時間時,就不會拖累其他實時性要求較高的線程的執行。
前幾天在客戶現場調試設備時,客戶的程序開了一個線程來兜各個狀態,並顯示各個動作所花費的時間,用鼠標拖拽界面進行移動時,CPU資源耗費很高,設備運 行的速度也隨之下降。爲了解決這個問題,我們想辦法將線程綁定到另一顆CPU上,實現方法如下。
首先用API函數創建一個線程,
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
SIZE_T dwStackSize, // initial stack size
LPTHREAD_START_ROUTINE lpStartAddress, // thread function
LPVOID lpParameter, // thread argument
DWORD dwCreationFlags, // creation option
LPDWORD lpThreadId // thread identifier
);
//通過調用SetThreadAffinityMask,就能爲各個線程設置親緣性屏蔽:
DWORD_PTR SetThreadAffinityMask(HANDLE hThread,
DWORD_PTR dwThreadAffinityMask);
//該函數中的h T h r e a d參數用於指明要限制哪個線程, dwThreadAffinityMask用於指明該線程能夠在哪個CPU上運行。dwThreadAffinityMask必須是進程的親緣性屏蔽的///相應子集。返回值是線程的前一個親緣性屏蔽。因此,若要將3個線程限制到CPU1、2和3上去運行,可以這樣操作:
//Thread 0 can only run on CPU 0.
SetThreadAffinityMask(hThread0, 0x00000001);
//Threads 1, 2, 3 run on CPUs 1.
SetThreadAffinityMask(hThread1, 0x0000000E);
經試驗,此方法解決了客戶拖拽界面導致整臺設備變慢的問題。
實例3:
多cpu下SetThreadAffinityMask運用框架
Author:zfive5(zidong)
Email :[email protected]
“舍”的目的,是爲了“得”!
隨着多cpu機器的普及時代的到來,大家對機器速度的提升感到欣喜若狂的同時,對cpu的掌控能力越來越差了,也許大家對這塊也不是特別注意或感興趣,但如果真等到需要這方面的答案時,又會無言,例如:
mov eax,1
這條指令在core2的機器上想在cpu1(這裏爲了區別另一個cpu而給它取的名稱罷了)上執行?而不是讓操作系統根據它的調度算法去選擇1或2,估計大家只能保持沉沒!感慨大家現在都讓操作系統包裝成了高科技的傻子,本着不想讓操作系統玩弄鼓掌的態度,我在msdn遊蕩了數小時,爲的是一個api的出現,終於SetThreadAffinityMask出現了,說真的此時的心情就像佛教徒們看到了佛祖猞猁那樣!關於SetThreadAffinityMask這個函數的介紹大家可以到msdn去搜!
下面寫一個SetThreadAffinityMask框架,大家去以後需要套用即可!
static DWORD WINAPI ZFive5Proc(LPVOID p)
{
//自己需要控制代碼開始
_asm{
push eax
mov eax,1
pop eax
}
sprintf((char*)p,"zfive5! good");
//自己需要控制代碼結束
return 0;
}
void CCPUDlg::OnOK()
{
// TODO: Add extra validation here
//CDialog::OnOK();
char szbuf[200];
DWORD id;
HANDLE hHandle=CreateThread(NULL,0,ZFive5Proc,&szbuf,CREATE_SUSPENDED ,&id);
if(hHandle==NULL)
{
AfxMessageBox("zfive5! error");
return;
}
//CPU1
SetThreadAffinityMask(hHandle,1);
//CPU2
//SetThreadAffinityMask(hHandle,2);
ResumeThread(hHandle);
if(WaitForSingleObject(hHandle,INFINITE)!=WAIT_OBJECT_0)
{
AfxMessageBox("zfive5! error");
CloseHandle(hHandle);
return;
}
CloseHandle(hHandle);
//TRACE("%s/r/n",szbuf);
AfxMessageBox(szbuf);
return;
}
這樣就可以讓線程的代碼ZFive5Proc在cpu1上執行了!
寫到這裏想起了我中熊貓燒香的經歷,就是鼠標點了一下跟目錄的圖標(windows隱藏了autorun.inf運行)!
昨天看kaspersky,發現它的界面是通過貼窗體來實現的!今天在同事的機器上看到macfee,發現界面很一般!