编程之美读书笔记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
编程之美读书笔记1.1——让CPU占用率曲线听你的指挥的更多相关文章
- 编程之美_1.1 让CPU占用率曲线听你指挥
听到有人说让要写一个程序,让用户来决定Windows任务管理器的CPU占用率. 觉得很好奇.但第一个想法就是写个死循环.哈哈.不知道具体的占用率是多少,但至少能保证在程序运行时,CPU的占用率终会稳定 ...
- 编程之美 1.1 让cpu占用率曲线听你指挥(多核处理器)
[目录] 不考虑其他进程,cpu画正弦曲线 获取总体cpu利用率 获取多核处理器单个cpu利用率 考虑其他进程,cpu画正弦曲线 下面的程序针对多核处理器,可以设置让任何一个cpu显示相应的曲线(本文 ...
- 编程之美读书笔记之 -寻找出现次数为1的ID的问题
问题描述: 在一张表里面保存了N个ID,有N-1个ID是出现了两次的,只有一个ID只出现了一次,现在要你把这个ID找出来.如果是两个呢? 解法一: 我们先来解决一个的.假如ID的值的范围是1-k, ...
- 编程之美 之 让CPU占用率听你指挥
昨天在bbs上淘到了这本编程之美.顺手刷了第一章,很有意思.第一章的要求是要控制CPU曲线,绘制出对应的形状. 拿到这个问题,我的第一反应是, 是不是有这么一个API,能在任务管理器上的对应区域直接绘 ...
- 《Linux/Unix系统编程手册》读书笔记 目录
<Linux/Unix系统编程手册>读书笔记1 (创建于4月3日,最后更新4月7日) <Linux/Unix系统编程手册>读书笔记2 (创建于4月9日,最后更新4月10日) ...
- 《Linux/Unix系统编程手册》读书笔记9(文件属性)
<Linux/Unix系统编程手册>读书笔记 目录 在Linux里,万物皆文件.所以文件系统在Linux系统占有重要的地位.本文主要介绍的是文件的属性,只是稍微提及一下文件系统,日后如果有 ...
- 《Linux/Unix系统编程手册》读书笔记8 (文件I/O缓冲)
<Linux/Unix系统编程手册>读书笔记 目录 第13章 这章主要将了关于文件I/O的缓冲. 系统I/O调用(即内核)和C语言标准库I/O函数(即stdio函数)在对磁盘进行操作的时候 ...
- 《Linux/Unix系统编程手册》读书笔记7 (/proc文件的简介和运用)
<Linux/Unix系统编程手册>读书笔记 目录 第11章 这章主要讲了关于Linux和UNIX的系统资源的限制. 关于限制都存在一个最小值,这些最小值为<limits.h> ...
- 《Linux/Unix系统编程手册》读书笔记6
<Linux/Unix系统编程手册>读书笔记 目录 第9章 这章主要讲了一堆关于进程的ID.实际用户(组)ID.有效用户(组)ID.保存设置用户(组)ID.文件系统用户(组)ID.和辅助组 ...
随机推荐
- LoadRunner测试ajax框架,回放后系统中没有产生数据解决方法
1.QTP11 下载地址:http://www.genilogix.com/downloads/unified-functional-testing/quicktest-professional-11 ...
- bzoj 1925 dp
思路:dp[ i ][ 0 ]表示第一个是山谷的方案,dp[ i ][ 1 ]表示第一个是山峰的方案, 我们算dp[ x ][ state ]的时候枚举 x 的位置 x 肯定是山峰, 然后就用组合数算 ...
- redis集群错误解决:/usr/lib/ruby/gems/1.8/gems/redis-3.0.0/lib/redis/client.rb:79:in `call': ERR Slot 15495 is already busy (Redis::CommandError)
错误信息: /usr/lib/ruby/gems/1.8/gems/redis-3.0.0/lib/redis/client.rb:79:in `call': ERR Slot 15495 is al ...
- 俄罗斯方块 Tetris
今天,为大家带来一个用Qt C++ (Windows环境下)做的一个简易俄罗斯方块小游戏 思路和模块介绍都在注释里面,其次就是一些项目中遇到的问题以及解决方案,在后面部分说明. 一.效果 测试图样 Q ...
- Python使用正则
Python中使用正则的两种方式 在Python中有两只能够使用正则表达式的方式: 直接使用re模块中的函数 import re re_string = "{{(.*?)}}" s ...
- opencv 加载 修改 保存 图像
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; /* 1 加载图像 cv::imre ...
- 【BZOJ 4558】 4558: [JLoi2016]方 (计数、容斥原理)
未经博主同意不能转载 4558: [JLoi2016]方 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 362 Solved: 162 Descri ...
- 选择排序之C++实现
选择排序之C++实现 一.源代码:SelectSort.cpp /* 选择排序(从小到大)的基本思想是,首先,选出最小的数,放在第一个位置: 然后,选出第二小的数,放在第二个位置: 以此类推,直到所有 ...
- BZOJ3611 HEOI2014大工程
先建虚树,然后统计答案. 对于这个两点间最大值和最小值的操作我参考了hzwer的代码. 建虚树时注意判自环 By:大奕哥 #include<bits/stdc++.h> using nam ...
- JZYZOJ 2002 [cf] 石江豪pk李震 博弈论 sg函数
http://172.20.6.3/Problem_Show.asp?id=2002 https://blog.csdn.net/qq_24451605/article/details/5015497 ...