题目:
写一个程序,让用户来决定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 %d ",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截图如下: