在Windows上,你可以为进程调用SetProcessAffinityMask,为线程调用SetThreadAffinityMask。然而,Windows似乎只公开GetProcessAffinityMask,而不是为进程的单个线程提供类似的API。
我有一个多线程程序,它在运行时将各个线程绑定到处理器。当我运行它时,我想(外部)查询哪个线程在哪个处理器上运行,以确保它正常工作。为此,我编写了一个小的命令行实用程序。但是我似乎找不到一种方法来找到单个线程绑定到哪个处理器或核心。
这显然是可能的;我在网上看到过adplus调试实用程序的描述,它能够显示类似堆栈的输出来显示线程关联。Process Explorer在多处理器机器上显示一个Threads选项卡,显示线程的"理想处理器"。
有人知道如何查询这条信息吗?
您可以通过两次调用SetThreadAffinityMask
来实现。这个函数返回传递的线程句柄的原始关联掩码。
所以…使用一个将affinity设置为一个CPU的掩码执行一次调用,然后执行第二次调用以恢复原始掩码。
这里是完整的C/c++源代码,包括错误检查:
DWORD GetThreadAffinityMask(HANDLE thread)
{
DWORD mask = 1;
DWORD old = 0;
// try every CPU one by one until one works or none are left
while(mask)
{
old = SetThreadAffinityMask(thread, mask);
if(old)
{ // this one worked
SetThreadAffinityMask(thread, old); // restore original
return old;
}
else
{
if(GetLastError() != ERROR_INVALID_PARAMETER)
return 0; // fatal error, might as well throw an exception
}
mask <<= 1;
}
return 0;
}
这段代码一次探测一个CPU,直到设置亲和性起作用(在这种情况下,我们现在知道了原始掩码!),或者直到初始1
从DWORD
移出。如果请求的CPU不可用,则ERROR_INVALID_PARAMETER
的函数失败,我们只尝试下一个。通常第一个CPU只会工作,所以它是相当高效的。
如果函数在ERROR_INVALID_PARAMETER
以外的情况下失败,这意味着我们没有足够的访问权限,或者系统有一些真正的问题,因为它不能满足我们的请求。因此,在这种情况下继续下去是没有意义的。
调用NtQueryInformationThread,使用ThreadBasicInformation:
typedef struct _THREAD_BASIC_INFORMATION
{
NTSTATUS ExitStatus;
PTEB TebBaseAddress;
CLIENT_ID ClientId;
ULONG_PTR AffinityMask;
KPRIORITY Priority;
LONG BasePriority;
} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
更快的方法是调用GetCurrentProcessorNumber
(参见msdn),它将返回当前线程在调用此函数时运行的处理器编号。
c#代码:
/// <summary>
/// Retrieves the number of the processor the current thread was running on <para/>
/// during the call to this function.
/// </summary>
/// <returns>The function returns the current processor number.</returns>
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int GetCurrentProcessorNumber();