7线程的调度优先级和亲缘性(7)

2019-05-18 23:22

GUIDELINES DESIGNINFO DISCARDABLE BEGIN

IDD_SCHEDLAB, DIALOG BEGIN

LEFTMARGIN, 7 RIGHTMARGIN, 202 TOPMARGIN, 7 BOTTOMMARGIN, 63 END END

#endif // APSTUDIO_INVOKED

#ifdef APSTUDIO_INVOKED

///////////////////////////////////////////////////////////////////////////// //

// TEXTINCLUDE //

1 TEXTINCLUDE DISCARDABLE BEGIN

\END

2 TEXTINCLUDE DISCARDABLE BEGIN

\ \END

3 TEXTINCLUDE DISCARDABLE BEGIN

\ \END

#endif // APSTUDIO_INVOKED

///////////////////////////////////////////////////////////////////////////// //

// Icon

//

// Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems.

IDI_SCHEDLAB ICON DISCARDABLE \#endif // English (U.S.) resources

/////////////////////////////////////////////////////////////////////////////

#ifndef APSTUDIO_INVOKED

///////////////////////////////////////////////////////////////////////////// //

// Generated from the TEXTINCLUDE 3 resource. //

/////////////////////////////////////////////////////////////////////////////

#endif // not APSTUDIO_INVOKED

7.10 亲缘性

按照默认设置,当系统将线程分配给处理器时, Windows 2000使用软亲缘性来进行操作。这意味着如果所有其他因素相同的话,它将设法在它上次运行的那个处理器上运行线程。让线程留在单个处理器上,有助于重复使用仍然在处理器的内存高速缓存中的数据。

有一种新的计算机结构,称为N U M A(非统一内存访问),在该结构中,计算机包含若干块插件板,每个插件板上有4个C P U和它自己的内存区。图7 - 6显示了一台配有3块插件板的计算机,总共有1 2个C P U,这样,任何一个线程都可以在1 2个C P U中的任何一个上运行。

图7-6 NUMA 计算机结构示意图

当C P U访问的内存是它自己的插件板上的内存时, N U M A系统运行的性能最好。如果C P U需要访问位于另一个插件板上的内存时,性能就会大大降低。在这样的环境中,就需要来自一个进程中的线程在CPU 0至3上运行,让另一个进程中的线程在CPU 4至7上运行,依次类推。为了适应这种计算机结构的需要,Windows 2000允许设置进程和线程的亲缘性。换句话说,可以控制哪个C P U能够运行某些线程。这称为硬亲缘性。

计算机在引导时,系统要确定机器中有多少个C P U可供使用。通过调用G e t S y s t e m I n f o函数(第1 4章介绍),应用程序就能查询机器中的C P U数量。按照默认设置,任何线程都可以调度到这些C P U中的任何一个上去运行。为了限制在可用C P U的子集上运行的单个进程中的线程数量,可以调用S e t P r o c e s s A ff i n i t y M a s k:

BOOL SetProcessAffinityMask(HANDLE hProcess, DWORD_PTR dwProcessAffinityMask);

第一个参数h P r o c e s s用于指明要影响的是哪个进程。第二个参数d w P r o c e s s A ff i n i t y M a s k是个位屏蔽,用于指明线程可以在哪些C P U上运行。例如,传递0 x 0 0 0 0 0 0 0 5表示该进程中的线程可以在CPU 0和CPU 2上运行,但是不能在CPU 1和C P U 3至3 1上运行。 注意,子进程可以继承进程的亲缘性。因此,如果一个进程的亲缘性屏蔽是0 x 0 0 0 0 0 0 0 5,那么它的子进程中的任何线程都拥有相同的位屏蔽,并共享相同的C P U。此外,可以使用作业内核对象将一组进程限制在要求的一组C P U上运行。

当然,还有一个函数也能够返回进程的亲缘性位屏蔽,它就是G e t P r o c e s s A ff i n i t y M a s k,如下面的代码所示:

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

这里也可以传递想要亲缘性屏蔽的进程句柄,该函数填入p d w P r o c e s s A ff i n i t y M a s k指向的变量。该函数还能返回系统的亲缘性屏蔽(在p d w S y s t e m A ff i n i t y M a s k指向的变量中)。系统的亲缘性屏蔽用于指明系统的哪个C P U能够处理线程。进程的亲缘性屏蔽始终是一个系统的亲缘性屏蔽的正确子集。

Windows 98 无论计算机中实际拥有多少个C P U,Windows 98只使用一个C P U。因此,G e t P r o c e s s A ff i n i t y M a s k总是用1填入两个变量中。

到现在为止,已经介绍了如何将进程的多个线程限制到一组C P U上去运行。有时可能想要将进程中的一个线程限制到一组C P U上去运行。例如,可能有一个包含4个线程的进程,它们在拥有4个C P U的计算机上运行。如果这些线程中的一个线程正在执行非常重要的操作,而你想增加某个C P U始终可供它使用的可能性,为此你对其他3个线程进行了限制,使它们不能在CPU 0上运行,而只能在CPU 1、2和3上运行。

通过调用S e t T h r e a d A ff i n i t y M a s k,就能为各个线程设置亲缘性屏蔽:

DWORD_PTR SetThreadAffinityMask(HANDLE hThread, DWORD_PTR dwThreadAffinityMask);

该函数中的h T h r e a d参数用于指明要限制哪个线程, d w T h r e a d A ff i n i t y M a s k用于指明该线程能够在哪个C P U上运行。d w T h r e a d A ff i n i t y M a s k必须是进程的亲缘性屏蔽的相应子集。返回值是线程的前一个亲缘性屏蔽。因此,若要将3个线程限制到CPU 1、2和3上去运行,可以这样操作:

//Thread 0 can only run on CPU 0.

SetThreadAffinityMask(hThread0, 0x00000001);

//Threads 1, 2, 3 run on CPUs 1, 2, 3.

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

Windows 98 由于计算机中无论配有多少个C P U,Windows 98只使用一个C P U,因此d w T h r e a d A ff i n i t y M a s k参数必须始终是1。

当一个x 8 6系统引导时,系统要执行相应的代码,以便测定主机上的哪些C P U遇到了著名的P e n t i u m浮点错误。系统必须为每个C P U测试其浮点错误,方法是将线程的亲缘性设置为第一个C P U,执行潜在的故障分割操作,并将结果与已知的正确答案进行比较。然后对下一个C P U进行上述同样的操作,如此等等。

注意在大多数环境中,改变线程的亲缘性就会影响调度程序有效地在各个C P U之间移植线程的能力,而这种能力可以最有效地使用C P U时间。表7 - 9显示了一个例子。

表7-9 线程的亲缘性示例

线程 A 4 优先级 亲缘性屏蔽 结果 0 x 0 0 0 0 0 0 0 CPU 0 1 0 x 0 0 0 0 0 0 0 CPU 1 3 0 x 0 0 0 0 0 0 0 不能运行 2 B 8 C 6 当线程A被唤醒时,调度程序发现该线程可以在CPU 0上运行,因此它被分配给CPU 0。然后线

程B被唤醒,调度程序发现该线程可以被分配给CPU 0或1,但是,由于CPU 0正在使用之中,因此调度程序将线程B分配给了CPU 1。至此,一切进行得都很顺利。

这时线程C被唤醒,调度程序发现它只能在CPU 1上运行。但是CPU 1正在被线程B使用着,它是个优先级为8的线程。由于线程C的优先级为6,因此它不能抢在线程B的前面运行。线程C可以抢在线程A的前面运行,因为线程A的优先级是4,但是调度程序不会使它抢在线程A的前面运行,因为线程C不能在CPU 0上运行。

这显示出为线程设置硬亲缘性将会对调度程序的优先级设置方案产生什么样的影响。 有时强制将一个线程分配给特定的C P U的做法是不妥当的。例如,有3个线程都只能在CPU 0上运行,而CPU 1、2和3则闲着无事可做。在这种情况下,如果告诉系统想让一个线程在某个C P U上运行,但是允许该线程在可能的情况下移到另一个C P U上去运行,那么这种办法会更好些。

若要为线程设置一个理想的C P U,可以调用S e t T h r e a d I d e a l P r o c e s s o r :

DWORD SetThreadIdealProcessor(HANDLE hThread, DWORD dwIdealProcessor);

h T h r e a d用于指明要为哪个线程设置首选的C P U。与我们已经介绍的其他函数不同,d w I d e a l P r o c e s s o r函数不是个位屏蔽函数,它是个从0到3 1的整数,用于指明供线程使用的首选C P U。可以传递一个M A X I M U M _ P R O C E S S O R S的值(在Wi n N T. h中定义为3 2),用于指明不存在理想的C P U。如果没有为该线程设置理想的C P U,那么该函数返回前一个理想的C P U或M A X I M U M _ P R O C E S S O R S。

也可以在一个可执行文件的头上设置处理器亲缘性。奇怪的是,似乎不存在它的链接程序开关,不过可以使用类似下面的代码:

// Load the EXE into memory. PLOADED_IMAGE pLoadedImage = ImageLoad(szExeName, NULL);

//Get the current load configuration information //for the EXE.

IMAGE_LOAD_CONFIG_DIRECTORY ilcd;

GetImageConfigInformation(pLoadedImage, &ilcd);

//Change the processor affinity mask. //I desire CPUs 0 and 1

ilcd.ProcessAffinityMask = 0x00000003;

//Save the new load configuration information. SetImageConfigInformation(pLoadedImage, &ilcd);

//Unload the EXE from memory. ImageUnload(pLoadedImage);

这里不想详细说明所有这些函数的情况,如果有兴趣的话,可以在Platform SDK文档中查看这些函数的具体情况。另外,可以使用称为I m a g e C f g . e x e的实用程序,以便改变可执行程


7线程的调度优先级和亲缘性(7).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:新课改背景下小学语文教师课堂教学评价语言探究-教育文档

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: