【问题标题】:How can you find the processor number a thread is running on?如何找到线程正在运行的处理器编号?
【发布时间】:2011-01-13 23:27:09
【问题描述】:

我有一个内存堆管理器,它根据系统上处理器的数量将堆划分为不同的段。内存只能分配在与当前运行线程的处理器一起使用的分区上。这将有助于让不同的处理器继续运行,即使两个不同的处理器想要同时分配内存,至少我相信。

我找到了适用于 Windows 的函数 GetCurrentProcessorNumber(),但这仅适用于 Windows Vista 及更高版本。是否有适用于 Windows XP 的方法?

另外,这可以在 POSIX 系统上使用 pthread 完成吗?

【问题讨论】:

  • 您知道随着时间的推移,大多数操作系统会在不同的内核上调度相同的线程吗?

标签: c linux memory-management pthreads windows-xp


【解决方案1】:

来自man sched_getcpu的输出:

NAME
       sched_getcpu - determine CPU on which the calling thread is running

SYNOPSIS
       #define _GNU_SOURCE
       #include <utmpx.h>

       int sched_getcpu(void);

DESCRIPTION
   sched_getcpu() returns the number of the CPU
   on which the calling thread is currently executing.

RETURN VALUE
   On success, sched_getcpu() returns a non-negative CPU number.
   On error, -1 is returned and errno is set to indicate the error.

SEE ALSO
   getcpu(2)

不幸的是,这是 Linux 特有的。我怀疑是否有一种可移植的方式来做到这一点。

【讨论】:

  • 快速浏览 pthread 文档并没有发现任何执行此操作的 phtread API 调用。
  • 谢谢伊利亚。虽然这仅适用于 Linux,但它是一个不错且干净的函数调用。如果/当我需要移植到另一个内核时,我可以将此函数调用更改为上述汇编程序的修改版本。
【解决方案2】:

对于 XP,快速谷歌显示如下:

https://www.cs.tcd.ie/Jeremy.Jones/GetCurrentProcessorNumberXP.htm这有帮助吗?

【讨论】:

  • 好的,谢谢。只要它在 x86 平台上运行,这似乎在 Linux 和 Windows 上都可以工作。
  • @Patrick 我不认为这适用于 Linux,无论如何只能在 XP 上运行。
  • 汇编语言本身不依赖于操作系统。至于_asm、__asm__、asm等在不同平台和编译器上的区别,我可以处理。
  • @Patrick 是的,刚刚在汇编文档中查找了它,它是一个实际指令,而不是像第一个想法那样的 API 调用......在 x86-64 linux 上也适用于我!
【解决方案3】:

除了 Antony Vennard 的回答和引用站点上的代码之外,这里还有适用于 Visual C++ x64 的代码(无内联汇编器):

DWORD GetCurrentProcessorNumberXP() {
   int CPUInfo[4];   
   __cpuid(CPUInfo, 1);
   // CPUInfo[1] is EBX, bits 24-31 are APIC ID
   if ((CPUInfo[3] & (1 << 9)) == 0) return -1;  // no APIC on chip
   return (unsigned)CPUInfo[1] >> 24;
}

在 Win7 x64 上的 GetCurrentProcessorNumber() 实现的简要介绍表明,它们使用不同的机制来获取处理器编号,但在我的(少数)测试中,我的自制函数和官方函数的结果是相同的.

【讨论】:

  • Cpuid 是一个序列化且极其昂贵的指令(想想 1000 个周期)。对于这里讨论的目的,当然不是一个合适的选择。假设您没有在数字生成器中花费 1000 个周期,那么随机选择一个堆会更好:-)
【解决方案4】:

如果您只想避免争用,则无需知道当前 CPU。你可以随机选择一个堆。或者你可以每个线程有一个堆。尽管您可能会或多或少地发生争用,但您可以避免轮询当前 CPU 的开销,这可能很重要,也可能不重要。另请查看英特尔线程构建模块的可扩展分配器,它可能已经比您更好地解决了这个问题。

【讨论】:

    【解决方案5】:

    这个设计对我来说很难闻。您似乎在假设线程将与特定 CPU 保持关联。这是不能保证的。是的,一个线程通常可以保留在单个 CPU 上,但它不是必须的,最终您的程序将有一个切换 CPU 的线程。它可能不会经常发生,但最终会发生。如果您的设计没有考虑到这一点,那么您很可能最终会遇到某种难以追踪的错误。

    让我问这个问题,如果在一个 CPU 上分配内存并在另一个 CPU 上释放内存会发生什么?您的堆将如何处理?

    【讨论】:

    • 释放处理器无关紧要。在每个块中,我保存一个指向正确分区的指针。我每次分配只调用一次函数,所以这不是问题。虽然当前线程确实可能会更改处理器,但这也不会导致我的设计出现任何问题(理论上:P)。堆本身仍然是一个锁定堆。因此,如果两个不同的线程想要在同一个分区上分配,一个将被锁定直到另一个完成。这种设计只是将一个处理器锁定另一个处理器的执行的可能性降到最低。
    • 问题大概是线程可能迁移同时分配内存。这可能会导致线程确定它在 CPU #0 上运行,获取指向堆 #0 的指针,然后迁移到 CPU #1,然后尝试从堆 #0 分配。
    • 没关系。我的堆本身就是一个锁定堆,所以即使没有这个处理器号黑魔法,它也能正常工作。我正在对其进行优化,以免锁定其他可能更有用的处理器。因此,在你们俩都指出的情况下,另一个处理器将被锁定而无法分配。不过,我设计的要点是,这不太可能发生,因此值得付出努力。
    • 设计非常好,它只需要假设内存是共享的(即通过 CAS 访问它),而实际上它几乎总是独占的。因此,没有共享写入 - 并且算法可以很好地扩展。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-06
    • 1970-01-01
    • 2010-11-01
    • 1970-01-01
    • 2014-11-15
    • 1970-01-01
    • 2017-06-06
    相关资源
    最近更新 更多