编程之美读书笔记1.1——让CPU占用率曲线听你的指挥

http://blog.csdn.net/pipisorry/article/details/36189155

<strong><span style="font-size:48px;color:#ff0000;">问题:</span></strong>写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率。

假设机器是多CPU,上面的程序会出现什么结果?怎样在多个CPU时显示相同的状态?比如。在双核的机器上,假设让一个单线程的程序死循环,能让两个CPU的使用率达到50%的水平么?为什么?多CPU的问题首先须要获得系统的CPU信息。能够使用GetProcessorInfo()获得多处理器的信息,然后指定进程在哪一个处理器上执行。

当中指定执行使用的是SetThreadAffinityMask()函数。

书中提到两个重要的API,GetProcessorInfo()与SetThreadAffinityMask()。经查询MSDN。GetProcessorInfo()是Windows Server上的API,在PC机上不好用。所以能够尝试GetSystemInfo()来获得核数。

实际上在Windows平台上直接用任务管理器就能够查看。任务管理器上会用四个窗体来显示CPU的使用情况(Windows7 酷睿i5-3230M)

四核都显示正弦曲线算法:

參考代码:

/*********************************************************************************************/
/* 控制cpu占用率曲线(50%直线、1~100随意直线、正弦曲线)皮皮 2014-6-30 */
/********************************************************************************************/
#include <Windows.h>
#include <stdio.h>
#include <math.h>
using namespace std;

const int SAMPLE_NUM = 200;
DWORD busy_time[200];
const DWORD TOTAL_TIME_SLICE = 100; //每隔100ms取下一个採样点。让cpu工作在相应振幅的时间
const DWORD HALF_TOTAL_TIME_SLICE = TOTAL_TIME_SLICE/2;
//sine 曲线
void sine(){
DWORD pre_time;
for(int i = 0 ; ; i = (i+1)%SAMPLE_NUM ){
pre_time = GetTickCount();
while( (GetTickCount() - pre_time) <= busy_time[i]);//cpu忙
Sleep(TOTAL_TIME_SLICE - busy_time[i]);//cpu闲
}
}

const double PI_L = 0.031415926535;
//对sine採样
void sine_sampling(){
for(int i = 0 ; i < SAMPLE_NUM ; i++){
busy_time[i] = (DWORD)( sin( PI_L*i )*HALF_TOTAL_TIME_SLICE + HALF_TOTAL_TIME_SLICE );//busy_time值范围 (-1~1) *50+50 = (0~100)
//printf("busy_time[%d] = %d\n",i,busy_time[i]);
}
}

void main(){
sine_sampling();

//printf("CurrentProcessorNumber : %d\n",(int)GetCurrentProcessorNumber());
SYSTEM_INFO info;
    GetSystemInfo(&info); //调用API函数来获取计算机硬件的信息
printf("dwNumberOfProcessors : %d\n",info.dwNumberOfProcessors);//cpu核数

DWORD dwThreadId;
HANDLE hThread;
int coreNum = info.dwNumberOfProcessors;
for(int i = 0 ; i < coreNum ; i ++){
hThread = CreateThread(0,0,(LPTHREAD_START_ROUTINE)sine,0,0,&dwThreadId);
SetThreadAffinityMask(hThread,1<<i);//针对cpu核i(from 0)
}
    WaitForSingleObject(hThread, INFINITE); //传入INFINITE表示无限等待
}

代码部分解释:

1.CreateThread

函数功能:创建线程

函数原型:

CreateThread(

__in_opt  LPSECURITY_ATTRIBUTES lpThreadAttributes,

__in      SIZE_T dwStackSize,

__in      LPTHREAD_START_ROUTINE lpStartAddress,

__in_opt __deref __drv_aliasesMem LPVOID lpParameter,

__in      DWORD dwCreationFlags,

__out_opt LPDWORD lpThreadId

);

函数说明:

第一个參数表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。

第二个參数表示线程栈空间大小。

传入0表示使用默认大小(1MB)。

第三个參数表示新线程所运行的线程函数地址,多个线程能够使用同一个函数地址。

第四个參数是传给线程函数的參数。

第五个參数指定额外的标志来控制线程的创建,为0表示线程创建之后马上就能够进行调度。假设为CREATE_SUSPENDED则表示线程创建后暂停执行。这样它就无法调度,直到调用ResumeThread()。

第六个參数将返回线程的ID号,传入NULL表示不须要返回该线程ID号。

函数返回值:成功返回新线程的句柄。失败返回NULL。

2.WaitForSingleObject

函数功能:等待函数 – 使线程进入等待状态。直到指定的内核对象被触发。

函数原形:

WaitForSingleObject(

__in HANDLE hHandle,

__in DWORD dwMilliseconds

);

函数说明:

第一个參数为要等待的内核对象。

第二个參数为最长等待的时间,以毫秒为单位,如传入5000就表示5秒。传入0就马上返回。传入INFINITE表示无限等待。

由于线程的句柄在线程执行时是未触发的。线程结束执行。句柄处于触发状态。所以能够用WaitForSingleObject()来等待一个线程结束执行。

函数返回值:在指定的时间内对象被触发。函数返回WAIT_OBJECT_0。超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。传入參数有错误将返回WAIT_FAILED

3.SetThreadAffinityMask()

函数功能:Sets a processor affinity mask for the specified thread.

函数原形:

WaitForSingleObject(

__in HANDLE hHandle,

__in DWORD dwMilliseconds

);

函数说明:

这个函数的參数有两个,第一个是运行任务的句柄,第二个是核的掩蔽码。

掩蔽码的使用规则是假设最低位置1,就将任务分派给编号为0的核,假设次低位置1,就将任务分派给编号为1的核。

假设掩蔽码设置为0xC。即编号为2, 3的核被置为1,线程就会在这两个核上切换。

more:

进程与指定cpu绑定:SetProcessAffinityMask(GetCurrentProcess(), dwMask);

线程与指定cpu绑定:SetThreadAffinityMask(GetCurrentThread(),dwMask);

dwMask为CPU序号的或运算值:1(0001)代表仅仅执行在CPU1,2(0010)代表仅仅执行在CPU2。3(0011)代表能够执行在CPU1和CPU2,以此类推。

ref: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686247(v=vs.85).aspx

结果截图:

附:

1.TOTAL_TIME_SLICE 的计算

假设不考虑其他程序的CPU占用情况,能够在每一个核上开一个线程。执行指定的函数,实现每一个核的CPU占用率同样。

要让CPU的占用率。呈函数 y = calc(t) (0 <= y <= 1, t为时间,单位为ms )分布。仅仅要取间隔非常短的一系列点。觉得在某个间隔内。y值近似不变。

设间隔值为GAP。显然在指定t值附近的GAP这段时间内,

CPU占用时间为:busy = GAP * calc(t)。

CPU空暇时间为:idle = GAP – busy

因此,非常easy写出以下这个通用函数:

void solve(Func *calc)

{

  double tb = 0;

  while(1) {

    unsigned ta = get_time();

    double r = calc(tb);

    if (r < 0 || r > 1) r = 1;

    DWORD busy = r * GAP;

    while(get_time() - ta < busy) {}

    Sleep(GAP - busy);

    tb += GAP;

  }

}

假设CPU占用率曲线不是周期性变化,就要对每一个t值都要计算一次,否则。能够仅仅计算第一个周期内的各个t值,其他周期的直接取缓存计算结果。

以CPU占用率为正弦曲线为例,显然:y = 0.5 * (1 + sin(a * t + b))

其周期T = 2 * PI / a  (PI = 3.1415927),能够指定T值为60s即60000ms。则

能够确定a值为 2 * PI / T, 若在这60000ms内我们计算200次(c = 200),则GAP值为 T / c = 300ms.也就是说,仅仅要确定了周期和计算次数,其他几个參数也都确定下来。

2.CPU亲缘性(Affinity)介绍

依照默认设置。当系统将线程分配给处理器时,Windows使用软亲缘性来进行操作。这意味着假设全部其它因素同样的话,它将设法在它上次执行的那个处理器上执行线程。让线程留在单个处理器上。有助于反复使用仍然在处理器的内存快速缓存中的数据。

有一种新的计算机结构,称为NUMA(非统一内存訪问),在该结构中,计算机包括若干块插件板,每一个插 件板上有4个CPU和它自己的内存区。

当CPU訪问的内存是它自己的插件板上的内存时,NUMA系统执行的性能最好。假设CPU须要訪问位于还有一个插件板上的内 存时,就会产生巨大的性能减少。在这种环境中,就须要限制来自一个进程中的线程在共享同一个插件版的CPU上执行。为了适应这种计算机结构的须要。Windows同意你设置进程和线程的亲缘性。

换句话说。你能够控制哪个CPU能够执行某些线程。

这称为硬亲缘性。

请注意。子进程能够继承进程的亲缘性。

注意:

(1)不管计算机中实际拥有多少个CPU。Windows98及曾经系统仅仅使用一个CPU,上述API不被支持。

(2)在大多数环境中,改变线程的亲缘性就会影响调度程序有效地在 各个CPU之间移植线程的能力,而这样的能力能够最有效地使用CPU时间。

3.CreateThread()函数

它是Windows提供的API接口,在C/C++语言另有一个创建线程的函数_beginthreadex(),在非常多书上(包含《Windows核心编程》)提到过尽量使用_beginthreadex()来取代使用CreateThread()。这是为什么?http://blog.csdn.net/morewindows/article/details/7421759

ref:

http://blog.csdn.net/pipisorry/article/details/36189155

http://blog.csdn.net/morewindows/article/details/7421759

http://www.cnblogs.com/foreverinside/p/3577273.html

http://www.cnblogs.com/flyinghearts/archive/2011/03/22/1991965.html

http://blog.csdn.net/u012370255/article/details/28232153

时间: 2024-12-20 05:50:07

编程之美读书笔记1.1——让CPU占用率曲线听你的指挥的相关文章

编程之美学习笔记(一)-让CPU占用率曲线听你指挥

终于放假了,开始在家里看一本向同学借来被程序猿尊称的必看经典书之一---<编程之美>.这本书给我的第一感觉是,他不单单是一本介绍算法的书,更不是一本纯算法的书,更多的是跟生活的很多实际问题息息相关,让你能更多地思考当我们面对现实实际问题的时候如何用自己从之前书本学习到的理论的知识去解决他们,如何以理论联系实际.这个寒假都会更新从这本书中学习来的知识,也希望有相同兴趣的人可以一起共同交流.那么就开始进入正题吧. 如何让cpu占用率呈现直线或者正弦曲线呢,看完第一章节,最简单的无非是调整自己写的程

编程之美读书笔记1.8 - 小飞的电梯调度算法

http://blog.csdn.net/pipisorry/article/details/36688019 问题: 亚洲微软研究院所在的希格玛大厦一共有6部电梯.在高峰时间,每层都有人上下,电梯每层都停.实习生小飞常常会被每层都停的电梯弄的很不耐烦,于是他提出了这样一个办法: 由于楼层并不算太高,那么在繁忙的上下班时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层.所有乘客从一楼上电梯,到达某层后,电梯停下来,所有乘客再从这里爬楼梯到自己的目的层.在一楼的时候,每个乘客选择自己的目

《编程之美-读书笔记》-1 中国象棋将帅问题

时间:2014.05.27 地点:基地 ---------------------------------------------------------------------------------------- 一.指针和引用的区别 1.指针可以为空,引用不可以不空. 引用是一个对象的别用,定义一个引用时必须初始化,而声名指针时可以不指向任何对象,故使用指针时也常要做空的判断,而引用无需,因为引用总是绑定着一个对象. 2.指针可以改变指向,而引用不可以重新绑定新对象.(指针变异思迁,引用从

编程之美读书笔记1.2——中国象棋将帅问题

http://blog.csdn.net/pipisorry/article/details/36380669 问题:下过中国象棋的朋友都知道,双方的"将"和"帅"相隔遥远,并且它们不能照面.在象棋残局中,许多高手能利用这一规则走出精妙的杀招.假设棋盘上只有"将"和"帅"二子(如图1-3所示)(为了下面叙述方便,我们约定用A表示"将",B表示"帅"): A.B二子被限制在己方3×3的格子

cpu占用率曲线-笔记

我们知道要查看电脑的cpu占用率的话可以从任务管理器得知,进一步可以从->性能栏 看到CPU占用率的曲线的变化.今天看了编程之美的第一章第一节,看到对电脑cpu占用率的控制,控制CPU占用率曲线变化,达到特定的效果. cpu占用率曲线的刷新频率为1秒.要使在某一时刻CPU占用率达到目的中的百分比,可通过分配1秒内程序运行和休眠的时间的所占比,来达到.如在某1秒内,程序都处于休眠状态,那么,CPU占用率将达到0(理想化).反正,cpu占用率将达到100%. 第一种方法:基于计算程序所运行的电脑CP

编程之美读书笔记2.15 - 子数组之和的最大值(二维)

http://blog.csdn.net/pipisorry/article/details/39083073 问题: 求二维数组(矩阵)的子矩阵之和的最大值. 亦可见:http://poj.org/problem?id=1050 解法1:(解释见注释) 每个子矩阵由列长.行长和左上角的元素位置决定.如果我们指定左上角的元素位置 (i,j) 和列长 c,那么可以求所有这些子矩阵中和最大的.然后,变化列长 c,可以求以 (i,j) 为左上角的最大和子矩阵.最所有左上角位置再求最大和子矩阵,问题就解

编程之美读书笔记2.14 - 子数组之和的最大值

http://blog.csdn.net/pipisorry/article/details/39083281 问题: 1. 一个由N个整数元素的一维数组,求其所有子数组中元素和的最大值. 2. 如果数组首尾相邻,也就是允许子数组A[i],...,A[n-1],A[0],...,A[j]存在,求其所有子数组总元素和的最大值. 解法1: /* O(n^2) 遍历算法 */ static int maxSubarraySum1(int *a,int a_len){ int max_sum = INT

编程之美读书笔记之---”不要被阶乘吓到“

问题一:给定一个整数N,那么N的阶乘末尾有多少个0呢?例如N = 10, N! = 362800,N! 的末尾有两个0. 问题二:求N! 的二进制表示中,最低位1的位置. 问题一的解法一: 最简单的方法就是把N! 算出来,就可以知道末尾有多少个0了. 问题一的解法二: 我们这样想,末尾的0可以从哪里得到呢,10的倍数,例如像10,20,100....这样的,可以贡献0,还有就是2 * 5这样也可以得到一个0,不过我们可以发现,10其实也是从5得来的, 10 = 2 * 5, 20 = 4 * 5

编程之美 之 让CPU占用率听你指挥

昨天在bbs上淘到了这本编程之美.顺手刷了第一章,很有意思.第一章的要求是要控制CPU曲线,绘制出对应的形状. 拿到这个问题,我的第一反应是, 是不是有这么一个API,能在任务管理器上的对应区域直接绘制图形呢? 然后就去查找API, 可惜搜索能力不行,最终还是没有找到. 然后看书上的解释, 太棒了. 解决这道题目的核心是. CPU占用率的概念,应该是指 CPU忙的时间与总时间的比,他是一个平均值的概念.也就是说.通过控制CPU忙闲时间的比值,我们能够大致控制CPU的占用率. 通过这个思想能够 控