前几天无聊,按照《编程之美》第一题写了个控制CPU使用率的程序。本以为没什么,可是今天早上在ChinaUnix上看到完全复制书上的代码毫无原创的帖子居然很火。。。所以把自己的代码贴出来,供以后学习……
效果图如下:
其实程序的设计思想很简单,Windows任务管理器中CPU使用率基本上1s刷新一次,而CPU使用率其实就是在1s中CPU忙和闲时间的均值。因此,根据我们想要得到的CPU曲线的特点,我们首先做出忙闲时间的表,CPU根据忙闲时间选择执行或挂起。
代码如下:
#define COUNT 200
const double SPLIT = 0.01;
const double PI = 3.14159265;
const double SLOPE = 150;
const int INTERVAL = 300;
DWORD WINAPI SineThread(LPVOID Sine)
{
DWORD busySpan[COUNT];
DWORD idleSpan[COUNT];
int half = INTERVAL/2;
double radian = 0.0;
DWORD startTime;
int i;
for (i=0; i<COUNT; i++)
{
busySpan[i] = (DWORD)(half + half*sin(PI*radian));
idleSpan[i] = (DWORD)(INTERVAL - busySpan[i]);
radian += SPLIT;
}
i = 0;
while(1)
{
i %= COUNT;
startTime = GetTickCount();
while((GetTickCount()-startTime) <= busySpan[i])
;
Sleep(idleSpan[i]);
i++;
}
return 0;
}
DWORD WINAPI SawThread(LPVOID Saw)
{
DWORD busySpan[COUNT];
DWORD idleSpan[COUNT];
int half = INTERVAL/2;
double radian = 0.0;
DWORD startTime;
int i;
for (i=0; i<COUNT; i++)
{
busySpan[i] = (DWORD)(SLOPE*radian);
idleSpan[i] = (DWORD)(INTERVAL - busySpan[i]);
radian += SPLIT;
}
i = 0;
while(1)
{
i %= COUNT;
startTime = GetTickCount();
while((GetTickCount()-startTime) <= busySpan[i])
;
Sleep(idleSpan[i]);
i++;
}
return 0;
}
int main()
{
HANDLE hThread1, hThread2;
DWORD dwThreadId1, dwThreadId2;
hThread1 = CreateThread(NULL, 0, SineThread, 0, CREATE_SUSPENDED, &dwThreadId1);
hThread2 = CreateThread(NULL, 0, SawThread, 0, CREATE_SUSPENDED, &dwThreadId2);
SetThreadAffinityMask(hThread1, 1);
SetThreadAffinityMask(hThread2, 2);
ResumeThread(hThread1);
ResumeThread(hThread2);
SuspendThread(GetCurrentThread());
return 0;
}
其中INTERVAL可以视为周期,而COUNT和SPLIT分别为采样点数和步长,SLOPE就是斜率了。。。另外,对于双核而言,编程之美上的代码并不完美,于是按照书上的指点,使用SetThreadAffinityMask()将两个线程分别在每个核去执行。
Linux下代码完全仿照Windows写出,知识获取时间的函数不同,另外,使用usleep实现微秒级定时:
#define COUNT 200
#define SPLIT 0.01
#define PI 3.14159265
#define INTERVAL 100
double get_time()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec*1000+tv.tv_usec*1.0/1000); /* ms */
}
int main()
{
double busy_span[COUNT]; /* need to modify */
double idle_span[COUNT];
int half = INTERVAL/2;
double radian = 0.0;
double start_time;
int i;
for(i=0; i<COUNT; i++)
{
busy_span[i] = (double)(half + half*sin(PI*radian));
idle_span[i] = (double)(INTERVAL - busy_span[i]);
radian += SPLIT;
}
i = 0;
while(1)
{
i %= COUNT;
start_time = get_time();
while((get_time()-start_time) <= busy_span[i])
;
usleep(idle_span[i]*1000);
i++;
}
return 0;
}