查询线程(不是进程)处理器关联?

时间:2011-07-06 19:30:20

标签: windows multithreading winapi

在Windows上,您可以为进程调用SetProcessAffinityMask,为线程调用SetThreadAffinityMask。但是,Windows似乎只显示GetProcessAffinityMask而不是流程的各个线程的类似API。

我有一个多线程程序,可以在运行时将各个线程绑定到处理器。当我运行它时,我想(外部)查询哪些线程正在哪些处理器上运行,以确保它正常工作。我写了一个小的命令行实用程序来执行此操作。但我似乎无法找到一种方法来查找单个线程绑定的处理器或核心。

这显然必须是可能的;我在网上看到adplus调试实用程序的描述能够显示类似pstack的输出以显示线程关联。 Process Explorer在多处理器计算机上显示一个Threads选项卡,显示线程的“Ideal Processor”。

有谁知道如何查询这条信息?

3 个答案:

答案 0 :(得分:6)

您可以通过两次拨打SetThreadAffinityMask来完成此操作。此函数返回传递的线程句柄的原始关联掩码

所以...用一个掩码设置一个调用,设置一个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,则意味着我们要么对句柄没有足够的访问权限,要么系统遇到一些实际问题,因为它无法满足我们的请求。因此,在这种情况下继续是没有意义的。

答案 1 :(得分:5)

使用ThreadBasicInformation

调用NtQueryInformationThread
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;

AFAIK没有记录获得线程亲和力的方法。

答案 2 :(得分:0)

更快的方法是调用GetCurrentProcessorNumber,看msdn,它将返回当前线程在调用此函数期间运行的处理器的编号。

c#c​​ode:

/// <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();