【进程线程绑定CPU】总结

来源:互联网 发布:文件服务器java 编辑:程序博客网 时间:2024/05/18 00:03

本文整合了网上关于这块讲解比较详细的文章,转载者请注明!

本文参照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, // SDSIZE_T dwStackSize, // initial stack sizeLPTHREAD_START_ROUTINE lpStartAddress, // thread functionLPVOID lpParameter, // thread argumentDWORD dwCreationFlags, // creation optionLPDWORD 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 :zfive5@yahoo.com.cn

“舍”的目的,是为了“得”!

随着多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,发现界面很一般!


0 0
原创粉丝点击