线程关联掩码对当前线程有什么好处?

时间:2010-02-03 19:43:50

标签: c++ winapi setthreadaffinitymask performancecounter

我正在编写游戏引擎,我需要一种方法来获得精确而准确的“deltatime”值,从中获取当前用于调试的FPS以及限制帧速率(这对我们的项目非常重要)。 / p>

做了一些研究,我发现最好的方法之一就是使用WinAPI的QueryPerformanceCounter功能。必须使用GetTicksCount来阻止forward counter leaps,但它本身并不十分准确。

现在,QueryPerformanceCounter的问题在于它显然可能返回看起来像时间扭曲的值(即,调用可能会在过去的时间内相对于另一个调用返回一个值)。只有当使用给定处理器核心获得的值与使用另一个处理器核心获得的值进行比较时,才会发生这种情况,这导致我最终的问题促使我发布此帖子:

  1. 操作系统可以在线程已经运行时“重新分配”一个线程到另一个核心,或者是一个线程被分配给一个给定的核心,直到该线程死掉?
  2. 如果一个线程无法重新分配(这对我来说很有意义,至少),为什么我可以做SetThreadAffinityMask(GetCurrentThread(),mask)这样的事情? Ogre3D在其Ogre::Timer class (Windows implementation)中做到了这一点,我假设这是为了避免时间回归。但为了实现这一点,那么我必须考虑操作系统任意将线程从一个核心移动到另一个核心的可能性,这对我来说似乎很奇怪(不确定原因)。
  3. 我认为这就是我现在想知道的。感谢。

6 个答案:

答案 0 :(得分:2)

除非线程具有处理器关联掩码,否则调度程序会将其从处理器移动到处理器以便为其提供执行时间。由于在处理器之间移动线程会降低性能,因此它将尝试不移动它,但是给它执行的处理器优先于不移动它。所以,通常是线程移动。

至于计时器apis。 timeGetTime专为多媒体计时而设计,因此比GetTickCount更准确。

QueryPerformanceCounter().仍然是您最精确的衡量标准。微软有这样的说法。

  

在多处理器计算机上,调用哪个处理器无关紧要。但是,由于基本输入/输出系统(BIOS)或硬件抽象层(HAL)中的错误,您可以在不同的处理器上获得不同的结果。要指定线程的处理器关联,请使用SetThreadAffinityMask函数。

因此,如果您正在特定计算机上进行计时测试,您可能不必担心QPC会倒退,您应该进行一些测试,看看它是否对您的计算机有影响。

答案 1 :(得分:1)

线程可以是,并且在线程运行时重新分配(除非它们具有关联集)。 Windows将负载分散到所有处理器上以最大限度地提高性能。

答案 2 :(得分:1)

即使您使用SetAffinityMask将线程锁定到一个处理器,如果您真的不走运并且硬件很糟糕,QPC也可以向后运行。最好只处理QPC返回错误值的情况。在Windows 7中,QPC在这方面有了显着的改进,但是因为你正在编写一款游戏,你可能会以XP为目标而无法帮助你。

另外,不要设置线程亲和性,你可以自我僵局,引入奇怪的时间和性能上的错误,并且通常会让自己感到悲伤。

答案 3 :(得分:0)

1)线程可以将线程分配给具有备用处理时间的核心。这就是为什么你经常会在四核机器上看到使用50%的软件的原因,但当你使用所有四个中的一半来检查图表时。

2)见1;)

答案 4 :(得分:0)

使用SetThreadAffinity()通常是一个坏主意,除非线程只进行计时。如果将线程锁定到单个核心,则可以首先消除拥有多核系统的所有好处。您的应用程序无法再扩展。即使您启动应用程序的多个实例,它们仍将锁定到单个核心。

答案 5 :(得分:0)

我们通常必须在运行时间时将游戏锁定到单个线程中;我们发现没有有效的方法,因为在测量性能时需要亚微秒级分辨率。

使事情变得更容易的一件事是我们的引擎被切割成总是同时运行的广泛组件(例如游戏/逻辑“服务器”,输入/图形“客户端”,音频,渲染是他们自己的线程),所以我们做的是将每个线程锁定到自己的核心并独立计时。

同样,因为我们知道例如渲染循环总是在核0上,所以我们用它来计算帧速率。