CPU利用率问题:操作系统原理和API
问题的提出:写一个程序,使得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的情况下,程序是不一样的写法,此处不讨论。这道题主要考察对操作系统的理解。