问题描述
- 该问题的目标是在Windows上编写一个程序,以将 CPU 使用率保持在50%左右。
- 在 Windows 上,我们可以使用任务管理器或Perfmon.exe来监控 CPU 使用率。
- CPU 使用率应该在 50% 附近,因为操作系统中还有很多其他任务,我们只取 CPU 的大概使用率。
- CPU 可以是多核处理器或单核处理器,因此首选通用解决方案
问题的根源
最初的问题来自编程之美的第 1.1 章
个人在这个问题上的努力
环境
- 处理器:Intel i5-3470,4核,4线程
- 系统:Windows 7
- 开发环境:Visual Studio 2010,boost库
第一次尝试
我的第一次尝试没有考虑多核和多线程,所以它没有工作,但它提供了一个想法:如果我们想要处理器半负载,我们可以创建一个无限循环,它在一半时间休眠,并占用处理器的另一半。
我将跳过第一次尝试的细节。
第二次尝试
在我的第二次尝试中,一切都很顺利,但仍有一些问题困扰着我。
我的第一个解决方案
以下片段是第一个可能的解决方案。它使用GetTickCount()
Windows API,并使用两个线程使处理器加载到 50%。
解决方案一要旨。
#include <boost/thread.hpp>
#include "windows.h"
#define INTERVAL 10
void infiniteLoop() {
while (1) {
DWORD startTime = GetTickCount();
while (GetTickCount() - startTime <= INTERVAL)
;
boost::posix_time::millisec sleepTime(INTERVAL);
boost::this_thread::sleep(sleepTime);
}
}
int main() {
boost::thread thread1(infiniteLoop);
boost::thread thread2(infiniteLoop);
thread1.join();
thread2.join();
char c;
std::cin >> c;
}
解决方案是成功的,但我不太明白为什么我只能使用两个线程来让 CPU 加载一半,因为 i5-3470 处理器是四核处理器,理论上,我只能使用 25% 加载处理器两个线程。
为什么我使用两个线程而不是四个线程?
一开始我以为处理器是双核处理器,XD。
Q1:这是我的第一个问题:为什么这两个线程infiniteLoop()
会消耗 50% 的 qual-core CPU 容量?
我努力解决这个问题,但我真的没有能力自己做......:X
我的第二个解决方案
第二个解决方案与第一个解决方案完全相同,只是我使用clock()
fromtime.h
来替换GetTickCount()
功能。在这个解决方案中,我真的需要 4 个线程才能使处理器加载到 50%。
这是代码。
#include <boost/thread.hpp>
#include "windows.h"
#include <ctime>
#define INTERVAL 10
void infiniteLoop() {
while (1) {
clock_t startTime = clock();
while (clock() - startTime <= INTERVAL)
;
boost::posix_time::millisec sleepTime(INTERVAL);
boost::this_thread::sleep(sleepTime);
}
}
int main() {
boost::thread thread1(infiniteLoop);
boost::thread thread2(infiniteLoop);
boost::thread thread3(infiniteLoop);
boost::thread thread4(infiniteLoop);
thread1.join();
thread2.join();
thread3.join();
thread4.join();
char c;
std::cin >> c;
}
这个方案让处理器的总使用率几乎在50%左右,但是通过观察任务管理器->性能->CPU记录,我发现四个核心的使用率并不是均匀分布的,前两个核心的负载几乎是60 %,第三个大约是50%,最后一个只是最大负载的30%左右。
所以这是我的第二个问题。
Q2:为什么这些内核没有均匀加载,这个现象背后是操作系统内部存在某种机制吗?
我的第三个解决方案
另一个想法是完全阻塞两个线程,从而使 CPU 负载为 50%。
这是代码。
#include <boost/thread.hpp>
#include "windows.h"
#include <iostream>
void infiniteRunningLoop() {
while (1) {
;
}
}
int main() {
boost::thread thread1(infiniteRunningLoop)
boost::thread thread2(infiniteRunningLoop)
thread1.join();
thread2.join();
}
关于三种解决方案的思考
- 这三个解决方案不是让 CPU 负载达到 50% 的通用解决方案,因为如果系统中运行其他程序,它们也会消耗 CPU 容量。
- 该解决方案仅适用于四核处理器,如果要在其他处理器上使用,例如双核处理器,则必须修改线程数。
- 这三个解决方案都不是优雅的..XD
那么,Q3:有人可以提供一个优雅的解决方案,可以实现目标并且可以在不同类型的处理器之间移植吗?
非常感谢那些阅读问题的人,更感谢那些可能提前回答这个问题的人!
XD