乍一看,这看起来不像是漂亮但正确的 C++ 或 C(确定它的简单方法是编译它)。缺少包含 ( <windows.h>
,<process.h>
和<time.h>
) 但否则它编译得很好。
请注意,clock
andSleep
并不是非常准确,Sleep
也不是非常可靠。不过,平均而言,线程函数应该按预期工作(给予或接受几个百分比的变化)。
但是,关于问题 2),您应该将最后一个替换为while(1){}
阻塞而不是旋转的东西(例如WaitForSingleObject
,或者Sleep
如果您愿意)。否则整个程序在四核上将不会有 50% 的负载。由于主线程,您将在一个核心上拥有 100% 的负载,再加上您的四个工作人员的 4x 50%。这显然会使每个核心的总和超过 50%(并且会导致线程从一个核心反弹到另一个核心,从而产生令人讨厌的副作用)。
使用任务管理器或类似的实用程序来验证您是否获得了所需的负载是一个不错的选择(因为它是最简单的解决方案,它也是最好的解决方案)。
另请注意,以这种方式模拟负载可能会起作用,但不是 100% 可靠。
可能存在难以预测的影响(内存、执行单元)。例如,假设您在这个循环中使用了 100% 的 CPU 整数执行单元(合理的假设),但它的浮点或 SSE 单元为零。现代 CPU 可能会在真实或逻辑内核之间共享资源,您可能无法准确预测得到的效果。或者,另一个线程可能是内存受限或有严重的页面错误,因此占用 CPU 时间不会像您想象的那样影响它(实际上可能会给它足够的时间来使预取工作更好)。或者,它可能会阻止 AGP 传输。或者,还有一些你说不出来的东西。
编辑:
改进的版本,更短的代码,修复了一些问题,也可以按预期工作:
- 用于
clock_t
返回的值clock
(从技术上讲,这比使用非特殊typedef
的整数“更正确”。顺便说一句,这可能是原始代码无法按预期工作的原因,因为clock_t
它是 Win32 下的有符号整数。条件inif()
总是评估true
,所以工作人员几乎一直在睡觉,不消耗 CPU。
- 旋转时代码更少,数学更简单。计算未来 50 个滴答声的唤醒时间并旋转直到达到该时间。
- 用于
getchar
在最后阻止程序。这不会消耗 CPU 时间,它允许您按 结束程序Enter。线程没有像通常那样正确结束,但在这种简单的情况下,让操作系统在进程退出时终止它们可能是可以的。
- 与原始代码一样,这假定
clock
并Sleep
使用相同的刻度。这无疑是一个大胆的假设,但在您在原始代码中使用的 Win32 下它是正确的(两个“滴答”都是毫秒)。C++ 没有类似的东西Sleep
(没有boost::thread
, 或 C++11 std::thread
),所以如果打算使用非 Windows 可移植性,无论如何你都必须重新考虑。
- 与原始代码一样,它依赖于不精确且不可靠的函数 (
clock
和)。在我的系统上等于而不使用. 尽管如此,该程序“几乎完美”地运行,导致我的机器上的负载为 50% +/- 0.5%。Sleep
Sleep(50)
Sleep(63)
timeBeginPeriod
与原始代码一样,这没有考虑线程优先级。具有高于正常优先级的进程将完全不会被此限制代码所打动,因为这就是 Windows 调度程序的工作方式。
#include <windows.h>
#include <process.h>
#include <time.h>
#include <stdio.h>
void task1(void *)
{
while(1)
{
clock_t wakeup = clock() + 50;
while(clock() < wakeup) {}
Sleep(50);
}
}
int main(int, char**)
{
int ThreadNr;
for(int i=0; i < 4; i++) _beginthread( task1, 0, &ThreadNr );
(void) getchar();
return 0;
}