网上有很多关于控制CPU曲线的文章,大部分是从《编程之美》上的题目得到的解决思路。本文从网上的文章进行了参考借鉴,对相应的程序进行了修改。主题框架是从网上借鉴的。加进了部分修改和整理,以及修改过程中的知识点。
1、解决思路
CPU占用率=1秒内CPU执行命令的时间/1秒,想控制CPU占用率曲线即控制CPU忙时间同CPU空闲时间的比值。比如1秒内,有0.5秒(500 毫秒)为CPU忙的时间,剩下的时间0.5秒为空闲时间,则其占用率为50%。
如何令CPU忙呢?大部分为让程序执行空语句,这里空语句转换成机器指令大概为5条语句(这个结果是通过汇编语言推断出来的结果)。
这里补充一下关于CPU执行命令快慢的参数的知识。主频是我们判断CPU计算速度快慢的重要参数。比如本人电脑的CPU为1.9GHz,4核,它代表一秒可以执行4*1.9*10^9次运算周期(这里说的有点不专业),每个周期可以执行两条指令。也就是说每秒可以执行2*4*1.9*10^9条指令,这里的指令是指机器语言的指令。(我们用C++编写的指令需编译链接后才可转换为机器指令其条数也会发生变化,一搬会变多,比如一个空语句转换为机器指令可以转换为5条指令)。
这一点说明我们也可以通过控制执行语句的条数来控制CPU忙的时间,本文采用控制CPU忙的时间来实现控制CPU占用率的目的。
让CPU空闲,本文使用Sleep()函数。
具体代码为:
while(1)
{
startTime= GetTickCount(); //获得当前时间(单位为毫秒)
while((GetTickCount()-startTime)<=(INTERVAL/2)); //控制程序忙时间
Sleep(INTERVAL/2); //控制CPU空闲时间
}
以上代码为较核心代码。
具体程序代码为:
#include <windows.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#define COUNT 200 //数组个数
const double SPLIT = 0.01; //间隔
const double PI = 3.14159265; //常数
const double SLOPE = 200; //锯齿幅度
const int INTERVAL = 100; //正选波幅度
using namespace std;
DWORD WINAPI SineThread(LPVOID Sine) //创建可以产生CPU曲线的线程
{
DWORD busySpan[COUNT]; //数组,存储空语句运算次数
DWORD idleSpan[COUNT]; //存储sleep语句运算次数
int half = INTERVAL/2; //为sin函数找中间值
double radian = 0.0; //从0-1的增长
DWORD startTime;
int i;
for (i=0; i<COUNT; i++) //构造正选型信号数组
{
busySpan[i] = (DWORD)(half + half*sin(2*PI*radian));
idleSpan[i] = (DWORD)(INTERVAL - busySpan[i]);
int a=0;
a=radian;
radian = radian-a;
radian += SPLIT;
//cout<<radian<<endl;//radian从0到1变化
}
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]; //空闲数组
double radian = 0.0; //斜率,或者说新的百分比
//double BUCHANG=200;
DWORD startTime;
int i;
for (i=0; i<COUNT; i++) //COUNT=200
{
//i %= INTERVAL;//INTERVAL=300
int a=SLOPE*radian;
busySpan[i] = (DWORD)(a%100); //SLOPE=200
idleSpan[i] = (DWORD)(INTERVAL - busySpan[i]);
radian += SPLIT; //间隔=0.075
}
i = 0;
while(1)
{
i %= COUNT;
startTime = GetTickCount();
while((GetTickCount()-startTime) <= busySpan[i])
;
Sleep(idleSpan[i]);
i++;
}
return 0;
}
DWORD WINAPI LineThread(LPVOID Line){
DWORD startTime;
while(1)
{
startTime= GetTickCount();
while((GetTickCount()-startTime)<=(INTERVAL/2));
Sleep(INTERVAL/2);
}
return 0;
}
int main()
{
HANDLE hThread1, hThread2;
HANDLE hThread3;
DWORD dwThreadId1, dwThreadId2;
DWORD dwThreadId3;
hThread1 =CreateThread(NULL, 0, SineThread, 0, CREATE_SUSPENDED, &dwThreadId1);//创建线程,在制定的CPU上运行
//hThread2 = CreateThread(NULL, 0, SawThread, 0, CREATE_SUSPENDED, &dwThreadId2);//创建线程,在指定的CPU上运行
hThread3 = CreateThread(NULL, 0, LineThread, 0, CREATE_SUSPENDED, &dwThreadId3);
SetThreadAffinityMask(hThread1, 1);
//SetThreadAffinityMask(hThread2, 0x00000001);
SetThreadAffinityMask(hThread3, 2);
ResumeThread(hThread1); //激活指定线程
//ResumeThread(hThread2);
ResumeThread(hThread3); //激活指定线程
SuspendThread(GetCurrentThread());
return 0;
}
得到的结果为:
特别说明:
SetThreadAffinityMask(hThread1,1);用于指定线程1在CPU0上运行。
本文尝试性的想让仅在第3个核心上运行均为成功,查找相关资料
SetThreadAffinityMask(hThread1,0x3);可以实现,均未成功。
还需进一步学习。
关于正弦曲线的参数控制,设计到两个参数SPLIT、INTERVAL,本人推导了一下他们同正弦曲线的周期T有如下关系:
INTERVAL/(1000*SPLIT)=T
大家可以理解为:
INTERVAL越大,T越大;
SPLIT越大,T越小。
这两个参数,可以用来控制正选曲线的显示周期。