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

因此,很容易写出下面这个通用函数:

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

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

  1. 编程之美读书笔记_1.1_让CPU占用率曲线听你指挥

    题目:写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率.程序越精简越好,计算机语言不限.例如,可以实现下面三种情况:   1.    CPU的占用率固定在50 ...

  2. 让多核CPU占用率曲线听你指挥(Windows实现)——《编程之美》1.1学习笔记

    让多核CPU占用率曲线听你指挥--<编程之美>1.1学习笔记 Problem: 写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率.有以下几种情况: ...

  3. 《编程之美》读书笔记23: 1.1 让CPU占用率曲线听你指挥

    题目:写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率.程序越精简越好,计算机语言不限.例如,可以实现下面三种情况:   1.    CPU的占用率固定在50 ...

  4. 编程之美:让CPU占用率曲线听你指挥

    题目:写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率.程序越精简越好,计算机语言不限.例如,可以实现下面三种情况: 1.    CPU的占用率固定在50%, ...

  5. (1.5.1.1)编程之美:让CPU占用率曲线听你指挥

    题目:写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率.程序越精简越好,计算机语言不限.例如,可以实现下面三种情况: 1.    CPU的占用率固定在50%, ...

  6. 【编程之美/读书笔记】Chapter 1 游戏之乐

    这里就不写每个问题的题目了,只是记录一下自己的总结和心得. 1.1 让CPU占用率听你指挥 这个题目我刚接触的想法是和多核多线程要扯上关系的,因为自己写个死循环只能跑到CPU 35%左右的占用率,但是 ...

  7. 编程之美 - 读书笔记 - 卖书折扣问题的贪心解法

    <编程之美>读书笔记(四):卖书折扣问题的贪心解法 每 次看完<编程之美>中的问题,想要亲自演算一下或深入思考的时候,都觉得时间过得很快,动辄一两个小时,如果再把代码敲一遍的话 ...

  8. Java并发编程之美读书笔记-并发编程基础2

    2019独角兽企业重金招聘Python工程师标准>>> 1.线程的通知与等待 Java中的Object类是所有类的父亲,鉴于继承机制,Java把所有类都需要的方法放到了Object类 ...

  9. 编程之美读书笔记2.1—求二进制数中1的个数

    解法一: 可以举一个8位二进制的例子.对于二进制操纵,我们除以一个2,原来数字就会减少一个0(向右移一位).如果除的过程中有余,那么久表示当前位置有一个1. 以10100010为例: 第一次除以2时, ...

  10. 编程之美--读书笔记--返回一个数组中所有元素被第一个元素除的结果

    笔试题目1:写一个函数,返回一个数组中所有元素被第一个元素除的结果 很多人会想到如下: void DivAarry(int *pArray,int size) { for(int i=size-1;i ...

最新文章

  1. 在oracle的安全策略中,Oracle数据库的安全策略(转)
  2. 汽车中的ECU, VCU, MCU, HCU
  3. Uber自动驾驶汽车被赶出了亚利桑那,近300人被裁
  4. 剑桥大学2020《AI全景报告》出炉,177页ppt
  5. 算法设计与分析 2 二维递推间接递推递归分析
  6. 初识微信小程序第一弹
  7. 下载服务 php,文件下载: 云---php服务---pc
  8. 从资深遥控器在家工作的5个技巧
  9. Chromedriver的安装
  10. Java中数字格式化format方法
  11. python字符串三,删除空白符,对齐函数及判断函数
  12. mysql wait_timeout=_Mysql的wait_timeout解决_MySQL
  13. 鼠标的默认事件之oncontextmenu及其案例
  14. maven pom 文件的 scope,scope=system 时打包打不进
  15. 网安学习-应急响应1
  16. java 缓存 框架_5个常用的Java分布式缓存框架
  17. excel按照颜色排序
  18. HTML5期末大作业:温泉酒店网站设计——中国风的温泉酒店网(13页) HTML+CSS+JavaScript 学生web网页制作期末大作业_住宿 旅游 主题酒店
  19. 宇宙生命进化的八大密度
  20. 2020年5月面试精心整理java面试题,覆盖了大部分面试题(附答案)

热门文章

  1. [转]Servlet 3.0 新特性详解
  2. 如何删除拒绝访问的文件
  3. 面向对象 阶段性总结
  4. 转: gob编解码
  5. CentOS设置时间
  6. .NET2.0 事务处理
  7. 信念很简单,把书念下去,然后走出去,不枉活一世 —转自动化所一篇博士论文致谢...
  8. 【基础】吴恩达机器学习笔记 - 线性回归 代价函数 梯度下降
  9. 【情感分析】基于Aspect的情感分析模型总结(PART IV)
  10. 【10.8】每日NLP学术论文推荐