这个问题的描述如下:写一个程序,让用户来觉得Windows的任务管理器(Task Messager)上的CPU占有率,编程语言不限。程序越精简越好,可以实现下面的功能:
第一、CPU的占有率固定在50%,为一条直线。
第二、CPU占有率为一条直线,占有率由命令行参数决定(范围是1-100)。
第三,CPU的占有率是一条正弦曲线。
在解这个题目之前,要先了解一下什么是CPU的占有率,从“占有”这两个字来看,CPU的占有率应该是CPU忙碌的时间占总时间的比率。题目中让我们控制CPU的占有率,就是让我们控制CPU什么时候忙碌,什么时候空闲,让它听从我们的指挥。
很容易,我们就想到了通过循环和判断来实现这个功能,在一半的时间内,我们让CPU运行自己的程序,另外一半,使用sleep,让CPU空闲,可以运转其他的程序,这个时间控制使用一个变量来控制,让变量自增或者自减。
解法一:在《编程之美》这本书里面讲的很清楚,循环确实可以做到,但是我们如何知道一个空循环所需要的时间呢,这个就需要自己估算了,在计算机中,任何程序到底层之后都会转换成机器指令,在接近机器指令的最近的语言就是汇编语言,我们可以通过分析汇编语言来分析一个空循环所需的时间。
LOOP:
mov dx i ;将i放入寄存器dx中
inc dx ;将dx自加1
mov i dx ;将寄存器中的值赋值给i
cmp i n ;判断i的值是否为n
jl loop ;循环
从这几行汇编语言中,我们可以看出来,一次循环需要运行5条机器指令,假设我们每个时钟周期可以执行两条以上的代码,CPU是频率是2.6GHZ,这是我的计算机CPU频率,这样没一秒钟就可以执行上述代码(2 600 000 000*2)/5 = 1 040 000 000次。但是我们的CPU空闲时间怎么确定呢,是不是直接就是一秒,也就是sleep(1000)就行了,答案是否。原因是在Windows下,CPU线程切换需要时间。在书上说的,CPU切换的时间片差不多就是10毫秒,这样我们就可以设定为sleep(10),得到的程序如下:
for(;;)
{
for(int i = 0; i < 10400000;i++);
Sleep(10);
}
不断调整循环次数,可以保证CPU的占有率曲线是一天直线,但是不是很稳定。该方法有一个很大的缺点就是,一旦换了一个CPU,我们必须重新计算循环次数。现在就需要一个动态的循环次数来适应CPU。
解法二:使用GetTickCount()函数得到系统从启动到现在所经历的毫秒数,也就是时间。代码如下:
void fun1()
{
int busyTime = 10;
int idleTime = busyTime * 1.0; //调整这个1.0的值,以达到50%的标准,不同的计算机上是不同的。
int ret = SetThreadAffinityMask(GetCurrentThread(),0x00000001);//使这个程序跑在第一个CPU核心
INT64 startTime = 0;
while (1){
startTime = GetTickCount();
while((GetTickCount() - startTime) <= busyTime)
;
Sleep(idleTime);
}
}
这种方法貌似可以,但是如果在操作系统中,其他进程也占有CPU资源的话,假如其他程序占有10%的CPU资源,那么本程序只能使用40%的CPU资源才能达到效果。这也不算是完全动态。