一、题目写一个程序,让windows任务管理器中的CPU占用率显示为一条正弦函数曲线

第一眼看到这个题目,本人确实是没有多大思路的。因为一直没有对性能和CPU占用上考虑太多。真正看书查资料弄完才觉得确实很不错的一个应用题。以下将一步步完成控制的任务。

二、本人运行环境:

操作系统:win 7 32位
CPU: intel i7 2630QM(2.0GHZ 4核8线程)

三、具体实现

1.  多CPU的解决办法

因为程序在多CPU下会效果显示混乱,所以需要代码来指定程序在哪个CPU下运行。

可以用Windows API来指定CPU,代码如下:

//让进程在指定处理器上运行(在第一个CPU上运行, 对多CPU的处理)    SetProcessAffinityMask(        GetCurrentProcess(),        0x00000001          //cpu mask         );

2. 控制CPU的思路

CPU有两种状态:
控制死循环
控制睡眠
Windows资源管理器:显示的CPU曲线是一条记录型的曲线,会记录CPU的当前的占用率,然后慢慢绘制成线。

3. 通过计算CPU频率来控制CPU

#include 
#include
#include "windows.h"//控制CPU , 需要计算CPU运行时间int main(){ //让进程在指定处理器上运行(在第一个CPU上运行, 对多CPU的处理) SetProcessAffinityMask( GetCurrentProcess(), 0x00000001 //cpu mask ); for(;;) { //CPU 2.0GHZ 4核心 8线程 //计算方法: 2.0*10的9次方 , 现代CPU每个时钟周期可以执行2条以上的代码 //2000 000 000*2/5=800 000 000 平均 for(int i=0;i<8000000;i++) ; Sleep(10);//10ms比较接近windows的调度时间片 } //system("PAUSE"); return 0;}

运行效果:

1366708936_3939.png
可以看出,效果不是很好。人工计算肯定是不准确的!而且其他程序也会占用CPU。

4. 通过GetTickCount()函数来设置时间间隔

GetTickCount()的作用是返回从操作系统启动到现在所经过的毫秒数。

这样做的好处就是不用估算CPU的频率了,较上面的方法肯定好多了。

#include 
#include
#include "windows.h"//控制CPUint main(){ //让进程在指定处理器上运行(在第一个CPU上运行, 对多CPU的处理) SetProcessAffinityMask( GetCurrentProcess(), 0x00000001 //cpu mask ); int busyTime = 100; int idleTime = busyTime; int start = 0; while(true) { //用系统函数省去了CPU运行时间的估算 start = GetTickCount(); while((GetTickCount() - start) <= busyTime) ; //空闲 Sleep(idleTime); } //system("PAUSE"); return 0;}

效果:

1366709898_7298.png
当然效果也一般,为下面的做铺垫。

5. 画正弦函数

要想画出正弦函数曲线,CPU忙的时间必须是慢慢递增的,然后递减。而CPU闲的时间必须是慢慢递减然后递增。
这样一个周期下来,最后一直循环重复即得到正弦函数曲线。
一下打印出部分忙闲时间关系:
1366710290_4458.png

代码:

#include 
#include
#include
#include
#include
const double SPLIT = 0.01;const int COUNT = 200;const double PI = 3.14159265;const int INTERVAL = 300; //间隔时间//画出一条正弦曲线int _tmain(int argc, _TCHAR* argv[]){ //让进程在指定处理器上运行(在第一个CPU上运行, 对多CPU的处理) SetProcessAffinityMask( GetCurrentProcess(), 0x00000001 //cpu mask ); //1. 设置忙与闲时的时间数组 DWORD busySpan[COUNT]; //array of busy times DWORD idleSpan[COUNT]; //array of idle times int half = INTERVAL / 2; double radian = 0.0; //弧度 for(int i = 0; i < COUNT; i++) { //sin(x)的取值范围是[-1,1],为了完整显示,必须给它作些参数调整 busySpan[i] = (DWORD)(half + (sin(PI * radian) * half)); idleSpan[i] = INTERVAL - busySpan[i]; radian += SPLIT; //每次增一点点 } //测试:输出忙与闲时的时间数组, 写入文件result.txt FILE *fp; fp = fopen("result.txt", "a+"); //a+表示追加方式 for(int i = 0; i < COUNT; i++) { //printf("busySpan[%d] is %d\n",i,busySpan[i]); //printf("idleSpan[%d] is %d\n\n",i,idleSpan[i]); fprintf(fp, "busySpan[%d] is %d\n" , i, busySpan[i]); fprintf(fp, "idleSpan[%d] is %d\n\n" , i , idleSpan[i]); } fclose(fp); //2. 画曲线 DWORD startTime = 0; int j = 0; while (true) { j = j % COUNT; //COUNT次为一个周期 startTime = GetTickCount(); while ((GetTickCount() - startTime) <= busySpan[j]) ; Sleep(idleSpan[j]); j++; } return 0;}

运行效果:
1366710363_5862.png
改变间隔时间INTERVAL = 100; 时可以相应使周期减小:
1366710440_7317.png

转载请注明出处

参考《编程之美》与 互联网