题目:
写一个程序,让用户来决定Windows任务管理器(task manager)的CPU占用率。程序越精简越好。计算机语言不限。
例如:可以实现下面三种情况:
1.CPU的占用率固定在50%,为一条直线;
2.CPU的占用率为一条直接,具体占用率由命令行参数决定(参数范围1~100);
3.CPU的占用率状态是一条正弦曲线。
首先解释一下什么是“CPU占有率”?
在任务管理器的一个刷新周期内,CPU忙(执行应用程序)的时间和刷新周期总时间的比率,就是CPU的占用率。也就是说,任务管理器中显示的是每个刷新周期内CPU占用率的统计平均值。
要操纵CPU的使用率曲线,就需要使CPU在一段时间在一段时间内(根据task manager的采样率)跑busy和idle两个不同的循环(loop),从而通过不同的时间比例,来调节CPU使用率。
Busy loop可以通过执行空循环来实现,Busy用可循环来实现,for(i=0;i<n;i++) ,并且可以利用GetTickCount()判断busy loop要循环多久;idle可以通过Sleep()来实现。 sleep(睡眠)函数,功能:执行挂起一段时间,头文件#include <windows.h>。
因此,可以写个程序,在一个刷新周期中,一会忙,一会闲,调节忙闲比例,来控制CPU占用率。
一个刷新时间到底是多久?且鼠标移动,后台程序等都会对曲线造成影响。单核多核条件下CPU占用率又会情况不同。
我的电脑CPU型号
对于问题:CPU的占用率固定在50%,为一条直线。
解法一:简单的解法
实现代码如下:
#include<stdio.h>
#include<unistd.h>
#include<windows.h>
int main(){
for(;;){
for(int i=0;i<9600000;i++)
;
Sleep(10);
}
return 0;
}
运行出来CPU截图:
在不断的调整参数后,有锯齿,近似一条直线。
在选取参数中,不能选的太小,如果选得太小,会造成线程频繁地被唤醒和挂起,无形中又增加了内核时间的不确定性。
这种方法要注意两种影响:
(1)尽量减少sleep/awake的频率,以减少操作系统内核调度程序的干扰。
(2)尽量不要调用system call(比如I/O这些privilege instruction),因为它也会导致很多不可控的内核运行时间。
这方法的缺点很明显:不能适应机器差异性。一旦换了CPU,就得重新估算n值。
解法二:使用GetTickCount()和Sleep()
实现代码如下:
#include<windows.h>
#include<stdio.h>
int main(){
int busyTime=10;
int idleTime=busyTime;
int startTime=0;
while(true){
startTime=GetTickCount();
//busy loop
while((GetTickCount()-startTime)<=busyTime)
;
//idle loop
Sleep(idleTime);
}
return 0;
}
运行出来的CPU截图:
截图结果与图一相似。
这两种解放都是假设目前系统上只有当前程序在运行,但实际上,操作系统中有很多程序会同时执行各种各样的任务,如果此刻其他进程使用了10%的CPU,那我们程序就只能使用40%的CPU,这样才能达到50%的效果。
解法三:能动态适应的解法
Perform是从Windows NT开始就包含在Windows管理工具组中的专业检测工具之一。Perform可获取有关操作系统,应用程序和硬件的各种效能技术器(perf counter)。
Microsoft.NET Framework提供了performanceCounter这一对象,可以方便地得到当前各种性能数据。包括CPU的使用率。
这种还没有弄出来
解法四:正弦曲线
把一条正弦曲线0~2n之间的弧度等分成200份进行抽样,计算每个抽样点的振幅
然后每隔300ms的时间取下一个抽样点,并让CPU工作对应振幅的时间。
#include<windows.h>
#include<stdlib.h>
#include<math.h>
const int SAMPLING_COUNT=200;//抽样点数量
const double PI=3.1415926535;//pi值
const int TOTAL_AMPLITUDE=300;// 每个抽样点对应的时间片
int main()
{
SetThreadAffinityMask(GetCurrentProcess(), 0x00000001);
DWORD busySpan[SAMPLING_COUNT]; //array of busy time
DWORD idleSpan[SAMPLING_COUNT]; //array of idle time
int amplitude=TOTAL_AMPLITUDE/2;
double radian=0.0;
double radianIncrement=2.0/(double)SAMPLING_COUNT;//抽样弧度的增量,也可以自己设置固定的增量大小
for(int i=0;i<SAMPLING_COUNT;i++)
{
busySpan[i]=(DWORD)(amplitude+(sin(PI*radian)*amplitude));
idleSpan[i]=TOTAL_AMPLITUDE-busySpan[i];
radian+=radianIncrement;
//printf("%d\t%d\n",busySpan[i],TOTAL_AMPLITUDE-busySpan[i]);
}
DWORD startTime=0;
//for(int j=0;;j=(j+1)%SAMPLING_COUNT){
// startTime=GetTickCount();
// while((GetTickCount()-startTime)<=busySpan[j])
// ;
// Sleep(TOTAL_AMPLITUDE-busySpan[j]);
// }
int j=0;
while(true)
{
j=j%SAMPLING_COUNT;
startTime=GetTickCount();
while((GetTickCount()-startTime)<=busySpan[j])
;
Sleep(idleSpan[j]);
j++;
}
return 0;
}
运行出的CPU截图如下: