在 Win32 上如何将线程移动到另一个 CPU 核心?
我想确保线程被移动到特定的 CPU 核心,并且永远不会被调度程序从它移走。
有 SetThreadAffinityMask()
调用,但没有 GetThreadAffinityMask()
。
我需要这个的原因是,如果调度程序将该线程移动到另一个 CPU,高分辨率计时器就会变得混乱。
I'd like to make sure that a thread is moved to a specific CPU core and can never be moved from it by the scheduler.
There's a SetThreadAffinityMask()
call but there's no GetThreadAffinityMask()
.
The reason I need this is because high resolution timers will get messed up if the scheduler moves that thread to another CPU.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您可以调用一个函数,该函数返回一个数字,指示线程正在哪个 CPU 上运行,而不使用关联性,那么一旦函数返回,答案通常会是错误的。 因此,在以提升的 IRQL 运行的内核代码之外,检查
SetThreadAffinityMask()
返回的掩码是尽可能接近的,并且 即使这样也在改变。听起来您正在尝试解决
RDTSC
时钟偏差问题。 如果您直接使用RDTSC
指令,请考虑改为调用QueryPerformanceCounter()
:QueryPerformanceCounter()
使用 HPET(如果芯片组支持并且位于系统的 ACPI 表中)。RDTSC
的应用程序没有任何作用。 AMD 双核优化器是针对直接使用 RDTSC 的应用程序的破解,但如果时钟偏差量由于 C1 时钟斜坡(其中时钟速度在 C1 电源状态下降低)而发生变化,您仍然会遇到时钟偏差。 而且这些实用程序可能不是很普遍,因此使用QueryPerformanceCounter()
的亲和力仍然是一个好主意。If you could call a function that returns a number indicating what CPU the thread is running on, without using affinity, the answer would often be wrong as soon as the function returned. So checking the mask returned by
SetThreadAffinityMask()
is as close as you're going to get, outside of kernel code running at elevated IRQL, and even that's changing.It sounds like you're trying to work around
RDTSC
clock skew issues. If you are using theRDTSC
instruction directly, consider callingQueryPerformanceCounter()
instead:QueryPerformanceCounter()
on Windows Vista uses the HPET if it is supported by the chipset and is in the system's ACPI tables.QueryPerformanceCounter()
, but this does nothing for applications that useRDTSC
directly. The AMD Dual-Core Optimizer is a hack for applications that useRDTSC
directly, but if the amount of clock skew is changing due to C1 clock ramping (where the clock speed is reduced in the C1 power state), you will still have clock skew. And these utilities probably aren't very widespread, so using affinity withQueryPerformanceCounter()
is still a good idea.您可能应该只使用 SetThreadAffinityMask 并相信它正在工作。
MSDN
You should probably just use SetThreadAffinityMask and trust that it is working.
MSDN
不需要 GetThreadAffinityMask。 只需获取 GetProcessAffinityMask 的值,关闭一些位,然后调用 SetThreadAffinityMask。 线程继承进程的亲和性掩码,并且由于它们的亲和性在您的控制之下,因此您已经知道线程的亲和性掩码(这是您设置的亲和性掩码)。
There is no need for GetThreadAffinityMask. Just get the value of GetProcessAffinityMask, turn some bits off, then call SetThreadAffinityMask. The threads inherit the process' affinity mask, and since their affinity is under your control, you already know a thread's affinity mask (it's the one you set it to).
肯说的话。 但如果您不相信它正在工作,您可以再次调用 SetThreadAffinityMask,并确认返回值与您期望的掩码相匹配。 (但是,当然,如果您不信任该函数,那么您就不能信任第二个调用...)
不要对 GetProcessAffinityMask 的存在感到困惑。 该函数不是用来验证 SetProcessAffinityMask 是否有效,而是用于构造一个线程亲和性,它是进程亲和性的子集。
只需查看返回值并验证它不是 0 就可以了。
What Ken said. But if you don't trust it's working, you can call SetThreadAffinityMask again, and confirm that the return value matches what you expect the mask to be. (But then of course, if you don't trust the function then you can't trust the second call...)
Don't be confused by the existence of GetProcessAffinityMask. That function is not there to verify that SetProcessAffinityMask worked, but e.g. so you can construct a thread affinity that is a subset of process affinity.
Just look that the return value and verify that it isn't 0 and you should be fine.