《Windows via C/C++》学习笔记 —— 线程的相关性

  默认情况下,Windows Vista(2000以上系统)使用“soft affinity”(软相关)的操作将线程分配给CPU。这意味着如果其他因素不变,系统运行线程的时候设法在该线程上次运行的那个CPU上运行该线程,以此重复使用仍然保存在CPU的cache中的数据。

  与“soft affinity”相对的是“hard affiinty”(硬相关),使用它可以控制哪个CPU运行哪些线程。

  在系统引导的时候,系统决定该计算机中有几个CPU可以被使用。在应用程序中,可以呼叫GetSystemInfo函数来取得CPU的数量。

  一般地,线程可以运行在任何一个CPU上,当然,你可以使用Windows自带的“soft affinity”机制,让Windows自动分配CPU给一个线程。

  或许,你更希望能够对分配给线程的CPU有一些限制,使用“hard affinity”机制。

  SetProcessAffinityMask函数限制一个特定的进程只能运行在CPU的一个子集上。

 

BOOL SetProcessAffinityMask(
   HANDLE hProcess,
   DWORD_PTR dwProcessAffinityMask);

 

  该函数得第一个参数指明了要被限制的进程,第二个参数是一个“位屏蔽”数据,里面的每个位表示一个CPU代号(从0开始标号),比如0x00000001表示选中CPU 0,也就是“该进程中的线程”只能运行在CPU 0上了;0x00000005表示同时选中CPU 0和CPU 2。

  一个进程中的子进程可以继承该进程的相关性,也可以使用作业内核对象对某些进程限制在要求的一组CPU上执行。

 

  可以调用GetProcessAffinityMask函数来取得一个进程相关性屏蔽信息。

 

BOOL GetProcessAffinityMask(
   HANDLE hProcess,
   PDWORD_PTR pdwProcessAffinityMask,
   PDWORD_PTR pdwSystemAffinityMask);

  该函数通过第二个参数返回指定进程的CPU的相关性信息,同时可以通过第三个参数返回系统相关性信息。系统相关性指明系统的哪些CPU可以处理线程,进程的相关性始终是系统相关性的子集。

 

  以上讨论的是如何把一个进程中的所有线程限制在一组CPU上。有的时候想要把进程的一个具体线程限制在一组CPU上。

  SetThreadAffinityMask函数可以限制某一个线程只能运行在一组CPU上。

DWORD_PTR SetThreadAffinityMask(
   HANDLE hThread,
   DWORD_PTR dwThreadAffinityMask);

 

  该函数的第二个参数的意义和SetProcessAffinityMask函数中的第二个参数相同。也必须指明了一个正确的CPU子集,限制指定的线程只能运行在这个CPU子集上。该函数返回原来的线程的相关信息。

  比如,现在有4个线程和4个可用的CPU,你想让线程1独占CPU 0,让其他3个线程只能运行在CPU 1、CPU 2、CPU 3上,可以如下编码:

SetThreadAffinityMask(hThread0, 0x00000001);
SetThreadAffinityMask(hThread1, 0x0000000E);
SetThreadAffinityMask(hThread2, 0x0000000E);
SetThreadAffinityMask(hThread3, 0x0000000E);

  使用“hard affinity”机制来强行限制一个线程只能运行在一组CPU上往往是不当的。这样会降低CPU的利用率。

  可用将一个理想的CPU分配一个线程。SetThreadIdealProcessor函数可用做到这一点:

DWORD SetThreadIdealProcessor(
   HANDLE hThread,
   DWORD dwIdealProcessor);

  该函数的第二个参数不是位屏蔽数据,而是一个0~31(32位系统)或0~63(64位系统)的整数。该数据指明首选的CPU。也可以传递MAXIMUM_PROCESSORS表明当前没有理想的CPU。

 

  可以在一个程序的开始阶段处理相关性,代码类似如下的代码:

// 加载一个EXE文件映像
PLOADED_IMAGE pLoadedImage = ImageLoad(szExeName, NULL);


// 取得刚才加载的EXE文件的配置信息

IMAGE_LOAD_CONFIG_DIRECTORY ilcd;
GetImageConfigInformation(pLoadedImage, &ilcd);

// 更改进程亲掾性

ilcd.ProcessAffinityMask = 0x00000003; // I desire CPUs 0 and 1

// 保存新的加载信息(包含刚才设置的亲掾性)

SetImageConfigInformation(pLoadedImage, &ilcd);
ImageUnload(pLoadedImage);     // 从内存卸载映像

 

posted on 2008-08-05 12:40  小虎无忧  阅读(5324)  评论(2编辑  收藏  举报

导航