【進程線程綁定CPU】總結

本文整合了網上關於這塊講解比較詳細的文章,轉載者請註明!

本文參照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,發現界面很一般!


發佈了19 篇原創文章 · 獲贊 13 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章