读编程之美:CPU占用率

  编程之美算是一本有趣的计算机书籍,上面说的东西也总能让我灰常灰常。。咳非常开心。所以我就整理一些出来吧。。

 

  编程之美开篇的第一个问题就是让任务管理器里面的CPU占用率能够显示成正弦曲线或者恒定的某个值。

 

首先,我们假设单核的情况下,要让CPU变成100%再简单不过了,一个while(true)死循环即可,那么具体起来的原理呢?我们看到在循环开始的过程中,CPU占用率也不是瞬间飙满的,而是像实际的方波一样,有一个过渡.所以,任务管理器的CPu占有率表示的是,在一个刷新周期内(1s)CPU忙的时间和刷新时间的比值.所以我们只要在一个周期里面控制忙和空的比率即可.

 

那么,第一个任务就是50%,其实,按照编程之美上的写法似乎是可以做到的,但是麻烦的是处理执行的循环次数需要自己去试

#include<Windows.h> int main(){ for(;;){ for(int i =0 ; i < 8000000; i++) ; //10ms比较接近windows的调度时间片 Sleep(10); } return 0; }

自己试了几次发现,把进程的Affinity设置为CPU1会比CPU0 相对来说得到更加稳定一些的曲线。。

《读编程之美:CPU占用率》

 

  如果需要这样进行不断测试才能得到一条破直线,也太没意思了。所以就需要一些比较猛的办法。编程之美里面的一个解法用GetTickCount()函数来让程序在设定好的busytime里面执行循环。而另外一个根据适应力的方法是用PerformanceCounter对象来实时处理数据。但是原理都大同小异,本质都是计算时间比来调节。此外,书上那个C#的程序似乎还有探讨余地,我也不用C#,没有自己试。

 

编程之美里面给出的正弦曲线的代码:

正弦曲线:

#include “Windows.h” #include “stdlib.h” #include “math.h” const double SPLIT = 0.01; const int COUNT =200; const double PI = 3.141592652; const int INTERVAL = 300; int main(){ //array of busy times DWORD busySpan[COUNT]; //array of idle times; DWORD idleSpan[COUNT]; int half = INTERVAL /2; double radian = 0.0; for(int i = 0 ; i < COUNT; i ++){ busySpan[i] = (DWORD) (half + (sin(PI * radian) * half) ); idleSpan[i] = INTERVAL -busySpan[i]; radian += SPLIT; } DWORD startTime= 0; int j= 0; while (true){ j = j% COUNT; startTime = GetTickCount(); while( (GetTickCount() – startTime) <= busySpan[j]) ; Sleep(idleSpan[j]); j++; } return 0; }

这段代码还是和之前一样,不过就是把一段正弦曲线用划分为1/SPLIT段,也就是COUNT部分,每个部分的值用sin(PI*radian)算出来。

通过改变INTERVAL的值能够获得不同程度的单次时间,在图上的表现就是一个周期的时间不同了。

 

《读编程之美:CPU占用率》

 

 

 

我的目标:

让双核CPU两个核的曲线呈相位差2/PI的正弦曲线

 

分析一下问题,其实和上面的正弦曲线没啥差别。但主要问题是多核CPU的时候需要使用多线程,并且分别给每个线程附加不同的循环。

#include<Windows.h> #include<WinBase.h> #include<stdio.h> #include<math.h> #include<process.h> #include<iostream> const double SPLIT = 0.01; const int COUNT =200; const double PI = 3.141592652; const int INTERVAL = 300; // startphrase = phraseyouWant/2*PI*200 DWORD WINAPI sineLoading(int startphrase){ //—————–code same to above—————- //array of busy times DWORD busySpan[COUNT]; //array of idle times; DWORD idleSpan[COUNT]; int half = INTERVAL /2; double radian = 0.0; for(int i = 0 ; i < COUNT; i ++){ busySpan[i] = (DWORD) (half + (sin(PI * radian) * half) ); idleSpan[i] = INTERVAL -busySpan[i]; radian += SPLIT; } DWORD startTime= 0; //—————————————————- int j= startphrase; while (true){ j = j% COUNT; //std::cout<<startphrase<<“Phrs:”<<j<<std::endl; startTime = GetTickCount(); while( (GetTickCount() – startTime) <= busySpan[j]) ; Sleep(idleSpan[j]); j++; } return 0; } int main(){ HANDLE handle[2]; DWORD dw[2]; int phr[2] = {0, 150}; for(int i = 0; i < 2; i ++){ //starting threads for processors handle[i] = CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE )sineLoading, (VOID*)phr[i], 0, dw) ; //Set thread affinity SetThreadAffinityMask(handle[i],i+1); } WaitForSingleObject(handle[1],INFINITE); return 0; }

  对于双核的情况,要点在于将不同的线程附加到不同的核心上。这里需要了解ThreadAffinityMask的概念,这个mask值表示了不同的核心,虽然文档里面写的是从0开始的,但是我自己机器上貌似要1,2才有用。结果就如下图了。

  期间用到了C++的多线程编程的概念。个人觉得这篇文章比较不错。

《读编程之美:CPU占用率》

 

问题:

  现在提出进一步的问题:怎么样在双核系统上只用一个进程(不能使用多线程/纤程)让两个CPU占用率都保持50%?

 

  思路,能够控制系统的线程迁移?或者换个思路,把一个死循环按时间分别附加到不同的CPU核心上?

    原文作者:cecilulysess
    原文地址: https://blog.csdn.net/cecilulysess/article/details/5466453
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞