问题的提出:写一个程序,使得CPU的占用率可以听从用户的安排,第一种情况,CPU的占用率固定在50%,第二种情况,CPU的占用率为一条直线,具体占用率用参数表示;第三种情况,CPU的占用率状态是一条正弦曲线。
分析:这个问题,不了解操作系统原理和内核代码的人看起来很玄乎。但此问题的本质是操作系统原理,即操作系统如何分配资源给用户程序。进而分析到应用程序级别可得,CPU忙的时间和CPU休眠的时间相等时,根据刷新出来的图像便保持在50%左右。写应用程序,会用到Windows的API。
思路一:根据CPU的主频,计算每秒钟执行的指令条数,将循环用汇编代码表示,求得需要循环执行的次数。并且休眠同样的时间。
核心的API:Sleep()
long GetCPUFreq()//获取CPU频率,单位: MHZ
{
int start1,start2;
_asm rdtsc
_asm mov start1,eax
Sleep(50);
_asm rdtsc
_asm mov start2,eax
return ((start2-start1)/50)/(1024);
}
//1-1
void SimpleCpu()
{
while(true)
{
//busy
for(int i=0;i<1181600000;i++)
;
//idle
Sleep(10);
}
}//simplecpu
思路二:使用GetTickCount()和Sleep()
使用GetTickCount获得系统启动以来的时间,然后根据需要休眠的时间确定忙循环要做的时间。
/GetTickCount和Sleep
void GetSleepCpu()
{
const DWORD busyTime=100; //10毫秒
const DWORD idleTime=busyTime; //忙的时间和休眠的时间大致相当
INT64 startTime=0;
while(true)
{
DWORD startTime=GetTickCount();
//bust loop
while((GetTickCount()-startTime)<busyTime)
;
//idle loop
Sleep(idleTime);
}
}//GetSleepCpu
思路三:正弦曲线问题
把2Pi等分,计算振幅,然后让CPU工作在相应的振幅处。
void SineGraph()
{
SetThreadAffinityMask(GetCurrentThread(), 1);
//将0-2Pi之间等分成200份进行抽样,计算每个抽样点的振幅
//300ms是近似的值 6.28/200
const int SAMPLINE_COUNT=200; //抽样点数量
const double PI=3.1415926535;
const int TOTAL_AMPLITUDE=300; //每个抽样点对应的时间片
DWORD busySpan[SAMPLINE_COUNT];
int apmlitude=TOTAL_AMPLITUDE;
double radian=0.0;
double radianIncrement=(2.0*PI)/(double)SAMPLINE_COUNT; //增量
//计算每个抽样点的振幅
for(int i=0;i<SAMPLINE_COUNT;i++)
{
busySpan[i]=(DWORD)(apmlitude+(sin(PI*radian)*apmlitude));
radian+=radianIncrement;
}
DWORD startTime=0;
for(int j=0;;j=(j+1)%SAMPLINE_COUNT)
{
startTime=GetTickCount();
while((GetTickCount()-startTime)<=busySpan[j])
;
Sleep(TOTAL_AMPLITUDE-busySpan[j]);
}
}//SineGraph
int _tmain(int argc, _TCHAR* argv[])
{
int c;
cin>>c;
switch(c)
{
case 1:
SimpleCpu(); //56%
break;
case 2:
GetSleepCpu(); //51% 52%
break;
case 3:
SineGraph(); //正弦曲线
break;
}
return 0;
}
多核CPU的情况下,程序是不一样的写法,此处不讨论。这道题主要考察对操作系统的理解。