您的位置:首页 > 编程语言

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

2014-03-04 16:50 393 查看
转载自/article/9232614.html

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

1. CPU的占用率固定在50%,为一条直线;

2. CPU的占用率为一条直线,但是具体占用率由命令行参数决定(参数范围1~ 100);

3. CPU的占用率状态是一个正弦曲线。

首先什么是CPU占用率?

在任务管理器的一个刷新周期内,CPU忙(执行应用程序)的时间和刷新周期总时间的比率,就是CPU的占用率,也就是说,任务管理器中显示的是每个刷新周期内CPU占用率的统计平均值。

因此可以写个程序,在一个刷新周期中,一会儿忙,一会儿闲,调节忙/闲比例,就可以控制CPU占有率!

一个刷新时间到底是多长,书上只是说,任务管理器观测,大约是1秒。鼠标移动、后台程序等都会对曲线造成影响!

单核环境下,空死循环会导致100%的CPU占有率。双核环境下,CPU总占有率大约为50%,四核会不会是25%左右呢?(没试过)

解法一:简单解法

Busy用可循环来实现,for(i=0;i<n;i++) ;

对应的汇编语言为

loop;

mov dx i ;将i置入dx寄存器

inc dx ;将dx寄存器加1

mov dx i ;将dx中的值赋回i

cmp i n ;比较i和n

j1 loop ;i小于n时则重复循环

我的cpu(双核) 2.53GHZ 现代cpu每个时钟周期可执行两条以上的代码,取平均值2,于是

(2520 000 000*2)/5=1012000000(循环/秒) 每秒可以执行循环1012000000次

不能简单的取n=10120000000然后sleep(1000),如果让cpu工作1s,休息1s很可能是锯齿,先达到一个峰值然后跌入一个很低的占有率;所以我们睡眠时间改为10ms,10ms比较接近windows的调度时间,n=10120000。如果sleep时间选的太小,会造成线程频繁的唤醒和挂起,无形中增加了内核时间的不确定性因此代码如下:

[cpp] view plaincopyprint?

#include <windows.h>

int main(void)
{
//50%
//Thread 0 can only run on CPU 0.
SetThreadAffinityMask(GetCurrentProcess(), 0x00000001);
while(true)
{
for(int i=0;i<10120000;i++)
;
Sleep(10);
}
return 0;

}

[cpp] view plaincopyprint?

#include <windows.h>

int main(void)
{

//50%

int busyTime=10;
int idleTime=busyTime;
_int64 startTime;
SetThreadAffinityMask(GetCurrentProcess(), 0x00000001);
while(true)
{
startTime=GetTickCount();
while((GetTickCount()-startTime)<=busyTime)
{
;
}
Sleep(idleTime);
}
return 0;
}

#include <windows.h>

int main(void)
{

//50%
int busyTime=10;
int idleTime=busyTime;
_int64 startTime;
SetThreadAffinityMask(GetCurrentProcess(), 0x00000001);
while(true)
{
startTime=GetTickCount();
while((GetTickCount()-startTime)<=busyTime)
{
;
}
Sleep(idleTime);
}
return 0;
}


截图为:

和解法一结果近似

上面两种解法都是假设当前系统只有当前程序在运行,但实际上,操作系统有很多程序会同时调试执行各种任务,如果此刻进程使用10%的cpu,那我们的程序只有使用40%的cpu才能达到50%的效果。

Perfmon.exe是从WIN NT开始就包含在windows管理工具中的专业检测工具之一。我们可以用程序来查询Perfmon的值,.Net Framework提供了PerformanceCounter这一对象,可以方便的查询当前各种性能数据,包括cpu使用率,因此解法三如下:

解法三:能动态适应的解法

[c-sharp]
view plaincopyprint?

using System;
using System.Diagnostics;
namespace cpu
{
class Program
{
static void Main(string[] args)
{
cpu(0.5);
}
static void cpu(double level)
{
PerformanceCounter p = new PerformanceCounter("Processor", "% Processor Time", "_Total");
if (p == null)
{
return;
}
while (true)
{
if (p.NextValue() > level)
System.Threading.Thread.Sleep(10);
}
}
}
}

[cpp] view plaincopyprint?

#include <windows.h>
#include <math.h>
int main(void)
{
SetThreadAffinityMask(GetCurrentProcess(), 0x00000001);
const double SPLIT=0.01;
const int COUNT=200;
const double PI=3.14159265;
const int INTERVAL=300;
DWORD busySpan[COUNT]; //array of busy time
DWORD idleSpan[COUNT]; //array of idle time
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;
}

#include <windows.h>
#include <math.h>
int main(void)
{
SetThreadAffinityMask(GetCurrentProcess(), 0x00000001);
const double SPLIT=0.01;
const int COUNT=200;
const double PI=3.14159265;
const int INTERVAL=300;
DWORD busySpan[COUNT]; //array of busy time
DWORD idleSpan[COUNT]; //array of idle time
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;
}


其中busySpan[i]=(DWORD)(half+(sin(PI*radian)*half));

idleSpan[i]=INTERVAL-busySpan[i];

这样保证了占有率=busy/(busy+idle)=(half+(sin(PI*radian)*half))/(2*half)=(1+sin(PI*radian))/2 在0到100%之间!。

结果截图:依然锯齿 近似正弦曲线吧。。。



下面更深入讨论,/article/6029615.html这篇博文很好,讨论了在双核情况下,每个cpu显示不同的曲线。如下:

控制CPU占用率,不仅仅是出于好玩而已。以前的某些程序,特别是某些老游戏,在新的机器上运行速度太快,必须先给CPU降速,才能顺利运行那些程序,有个共享软件CPUKiller,就是专门弄这个的。

控制CPU占用率,因为要调用Windows的API,要考虑到多核、超线程的情况,要考虑到不同版本的Windows的计时相关的API的精度不同,使问题变得相当复杂,若再考虑其它程序的CPU占用率,则该问题则变得很烦人。(taskmgr调用了一个未公开的API)。

对CPU核数的判断,书上是调用GetProcessorInfo,其实可以直接调用GetSystemInfo,SYSTEM_INFO结构的dwNumberOfProcessors成员就是核数。不知道超线程对这两种方法有什么影响。

如果不考虑其它程序的CPU占用情况,可以在每个核上开一个线程,运行指定的函数,实现每个核的CPU占用率相同

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

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

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

CPU空闲时间为:idle = GAP - busy

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

[cpp] view plaincopyprint?

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;
}
}

[cpp] view plaincopyprint?

#include<iostream>
#include<cmath>
#include<windows.h>

static int PERIOD = 60 * 1000; //周期ms
const int COUNT = 300;  //一个周期计算次数
const double GAP_LINEAR = 100;  //线性函数时间间隔100ms
const double PI = 3.1415926535898; //PI
const double GAP = (double)PERIOD / COUNT; //周期函数时间间隔
const double FACTOR = 2 * PI / PERIOD;  //周期函数的系数
static double Ratio = 0.5;  //线性函数的值 0.5即50%
static double Max=0.9; //方波函数的最大值
static double Min=0.1; //方波函数的最小值

typedef double Func(double);  //定义一个函数类型 Func*为函数指针
typedef void Solve(Func *calc);//定义函数类型,参数为函数指针Func*
inline DWORD get_time()
{
return GetTickCount(); //操作系统启动到现在所经过的时间ms
}
double calc_sin(double x)  //调用周期函数solve_period的参数
{
return (1 + sin(FACTOR * x)) / 2; //y=1/2(1+sin(a*x))
}
double calc_fangbo(double x)  //调用周期函数solve_period的参数
{
//方波函数
if(x<=PERIOD/2) return Max;
else return Min;
}

void solve_period(Func *calc) //线程函数为周期函数
{
double x = 0.0;
double cache[COUNT];
for (int i = 0; i < COUNT; ++i, x += GAP)
cache[i] = calc(x);
int count = 0;
while(1)
{
unsigned ta = get_time();
if (count >= COUNT) count = 0;
double r = cache[count++];
DWORD busy = r * GAP;
while(get_time() - ta < busy) {}
Sleep(GAP - busy);
}
}

void solve_linear(Func*)  //线程函数为线性函数,参数为空 NULL
{
const unsigned BUSY =  Ratio * GAP_LINEAR;
const unsigned IDLE = (1 - Ratio) * GAP_LINEAR;
while(1)
{
unsigned ta = get_time();
while(get_time() - ta < BUSY) {}
Sleep(IDLE);
}
}
//void solve_nonperiod(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;
//    tb += get_time() - ta;
//  }

//}

void run(int i=1,double R=0.5,double T=60000,double max=0.9,double min=0.1)
//i为输出状态,R为直线函数的值,T为周期函数的周期,max方波最大值,min方波最小值
{
Ratio=R; PERIOD=T; Max=max; Min=min;
Func *func[] = {NULL ,calc_sin,calc_fangbo};  //传给Solve的参数,函数指针数组
Solve *solve_func[] = { solve_linear, solve_period};  //Solve函数指针数组
const int NUM_CPUS = 2;  //双核,通用的可以用下面GetSystemInfo得到cpu数目
HANDLE handle[NUM_CPUS];
DWORD thread_id[NUM_CPUS]; //线程id
//SYSTEM_INFO info;
//GetSystemInfo(&info);   //得到cpu数目
//const int num = info.dwNumberOfProcessors;
switch(i)
{
case 1: //cpu1 ,cpu2都输出直线
{
for (int i = 0; i < NUM_CPUS; ++i)
{
Func *calc = func[0];
Solve *solve = solve_func[0];
if ((handle[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[i])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[i], i+1); //限定线程运行在哪个cpu上
}
WaitForSingleObject(handle[0],INFINITE);   //等待线程结束
break;
}
case 2: //cpu1直线,cpu2正弦
{
for (int i = 0; i < NUM_CPUS; ++i)
{
Func *calc = func[i];
Solve *solve = solve_func[i];
if ((handle[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[i])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[i], i+1); //限定线程运行在哪个cpu上
}
WaitForSingleObject(handle[0],INFINITE);   //等待线程结束
break;
}
case 3: //cpu1直线,cpu2方波
{

/*Func *calc = func[0];
Solve *solve = solve_func[0];*/
if ((handle[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve_func[0],
(VOID*)func[0], 0, &thread_id[0])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[0], 1); //限定线程运行在哪个cpu上
Func *calc = func[2];
Solve *solve = solve_func[1];
if ((handle[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[1])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[1], 2); //限定线程运行在哪个cpu上
WaitForSingleObject(handle[0],INFINITE);   //等待线程结束
break;
}
case 4: //cpu1正弦,cpu2方波
{
if ((handle[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve_func[1],
(VOID*)func[1], 0, &thread_id[0])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[0], 1); //限定线程运行在哪个cpu上
Func *calc = func[2];
Solve *solve = solve_func[1];
if ((handle[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[1])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[1], 2); //限定线程运行在哪个cpu上
WaitForSingleObject(handle[0],INFINITE);   //等待线程结束
break;
}
default: break;
}
}

void main()
{
run(1,0.5);  //cpu1 ,cpu2都输出50%的直线
//run(2,0.5,30000); //cpu1 0.5直线,cpu2正弦周期30000
//run(3);  //cpu1直线,cpu2方波
//run(4,0.8,30000,0.95,0.5); //cpu1正弦,cpu2 0.95-0.5的方波
}

#include<iostream>
#include<cmath>
#include<windows.h>

static int PERIOD = 60 * 1000; //周期ms
const int COUNT = 300;  //一个周期计算次数
const double GAP_LINEAR = 100;  //线性函数时间间隔100ms
const double PI = 3.1415926535898; //PI
const double GAP = (double)PERIOD / COUNT; //周期函数时间间隔
const double FACTOR = 2 * PI / PERIOD;  //周期函数的系数
static double Ratio = 0.5;  //线性函数的值 0.5即50%
static double Max=0.9; //方波函数的最大值
static double Min=0.1; //方波函数的最小值

typedef double Func(double);  //定义一个函数类型 Func*为函数指针
typedef void Solve(Func *calc);//定义函数类型,参数为函数指针Func*
inline DWORD get_time()
{
return GetTickCount(); //操作系统启动到现在所经过的时间ms
}
double calc_sin(double x)  //调用周期函数solve_period的参数
{
return (1 + sin(FACTOR * x)) / 2; //y=1/2(1+sin(a*x))
}
double calc_fangbo(double x)  //调用周期函数solve_period的参数
{
//方波函数
if(x<=PERIOD/2) return Max;
else return Min;
}

void solve_period(Func *calc) //线程函数为周期函数
{
double x = 0.0;
double cache[COUNT];
for (int i = 0; i < COUNT; ++i, x += GAP)
cache[i] = calc(x);
int count = 0;
while(1)
{
unsigned ta = get_time();
if (count >= COUNT) count = 0;
double r = cache[count++];
DWORD busy = r * GAP;
while(get_time() - ta < busy) {}
Sleep(GAP - busy);
}
}

void solve_linear(Func*)  //线程函数为线性函数,参数为空 NULL
{
const unsigned BUSY =  Ratio * GAP_LINEAR;
const unsigned IDLE = (1 - Ratio) * GAP_LINEAR;
while(1)
{
unsigned ta = get_time();
while(get_time() - ta < BUSY) {}
Sleep(IDLE);
}
}
//void solve_nonperiod(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;
//    tb += get_time() - ta;
//  }
//}

void run(int i=1,double R=0.5,double T=60000,double max=0.9,double min=0.1)
//i为输出状态,R为直线函数的值,T为周期函数的周期,max方波最大值,min方波最小值
{
Ratio=R; PERIOD=T; Max=max; Min=min;
Func *func[] = {NULL ,calc_sin,calc_fangbo};  //传给Solve的参数,函数指针数组
Solve *solve_func[] = { solve_linear, solve_period};  //Solve函数指针数组
const int NUM_CPUS = 2;  //双核,通用的可以用下面GetSystemInfo得到cpu数目
HANDLE handle[NUM_CPUS];
DWORD thread_id[NUM_CPUS]; //线程id
//SYSTEM_INFO info;
//GetSystemInfo(&info);   //得到cpu数目
//const int num = info.dwNumberOfProcessors;
switch(i)
{
case 1: //cpu1 ,cpu2都输出直线
{
for (int i = 0; i < NUM_CPUS; ++i)
{
Func *calc = func[0];
Solve *solve = solve_func[0];
if ((handle[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[i])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[i], i+1); //限定线程运行在哪个cpu上
}
WaitForSingleObject(handle[0],INFINITE);   //等待线程结束
break;
}
case 2: //cpu1直线,cpu2正弦
{
for (int i = 0; i < NUM_CPUS; ++i)
{
Func *calc = func[i];
Solve *solve = solve_func[i];
if ((handle[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[i])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[i], i+1); //限定线程运行在哪个cpu上
}
WaitForSingleObject(handle[0],INFINITE);   //等待线程结束
break;
}
case 3: //cpu1直线,cpu2方波
{

/*Func *calc = func[0];
Solve *solve = solve_func[0];*/
if ((handle[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve_func[0],
(VOID*)func[0], 0, &thread_id[0])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[0], 1); //限定线程运行在哪个cpu上
Func *calc = func[2];
Solve *solve = solve_func[1];
if ((handle[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[1])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[1], 2); //限定线程运行在哪个cpu上
WaitForSingleObject(handle[0],INFINITE);   //等待线程结束
break;
}
case 4: //cpu1正弦,cpu2方波
{
if ((handle[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve_func[1],
(VOID*)func[1], 0, &thread_id[0])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[0], 1); //限定线程运行在哪个cpu上
Func *calc = func[2];
Solve *solve = solve_func[1];
if ((handle[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[1])) != NULL)  //创建新线程
SetThreadAffinityMask(handle[1], 2); //限定线程运行在哪个cpu上
WaitForSingleObject(handle[0],INFINITE);   //等待线程结束
break;
}
default: break;
}
}

void main()
{
run(1,0.5);  //cpu1 ,cpu2都输出50%的直线
//run(2,0.5,30000); //cpu1 0.5直线,cpu2正弦周期30000
//run(3);  //cpu1直线,cpu2方波
//run(4,0.8,30000,0.95,0.5); //cpu1正弦,cpu2 0.95-0.5的方波
}


结果如下(双核)

run(1,0.5):





run(2,0.5,30000):





run(3):



run(4,0.8,30000,0.95,0.5):





结束语:蛋疼时候可以拿任务管理器当示波器玩。。。

补充几个函数的说明:

GetTickCount返回(retrieve)从操作系统启动到现在所经过(elapsed)的毫秒数,它的返回值是DWORD。函数原型:   DWORD GetTickCount(void);

C/C++头文件:winbase.h ;windows程序设计中可以使用头文件windows.h

Sleep()函数

C++中头文件<windows.h>下的函数 作用:延时,程序暂停若干时间。时间,就是他的参数,单位是毫秒。Sleep (500) ; //注意第一个字母是大写。就是到这里停半秒,然后继续向下执行。  在Linux C语言中 sleep的单位是秒 sleep(5); //停5秒 包含在 <unistd.h>头文件中

CreateThread,建立新的线程

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to security attributes

DWORD dwStackSize, // initial thread stack size

LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function

LPVOID lpParameter, // argument for new thread

DWORD dwCreationFlags, // creation flags

LPDWORD lpThreadId // pointer to receive thread ID

);

概述:

当使用CreateProcess调用时,系统将创建一个进程和一个主线程。CreateThread将在主线程的基础上创建一个新线程,大致做如下步骤:

1在内核对象中分配一个线程标识/句柄,可供管理,由CreateThread返回

2把线程退出码置为STILL_ACTIVE,把线程挂起计数置1

3分配context结构

4分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD

5lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数

6把context结构的栈指针指向栈顶(第5步)指令指针指向startOfThread函数

语法:

hThread = CreateThread (&security_attributes,dwStackSize,ThreadProc,pParam,dwFlags, &idThread) ;

参数说明:  

第一个参数是指向SECURITY_ATTRIBUTES型态的结构的指针。在Windows 98中忽略该参数。在Windows NT中,它被设为NULL。第二个参数是用于新线程的初始堆栈大小,默认值为0。在任何情况下,Windows根据需要动态延长堆栈的大小。

  CreateThread的第三个参数是指向线程函数的指针。函数名称没有限制,但是必须以下列形式声明:

DWORD WINAPI ThreadProc (PVOID pParam) ;

 CreateThread的第四个参数为传递给ThreadProc的参数。这样主线程和从属线程就可以共享数据。

  CreateThread的第五个参数通常为0,但当建立的线程不马上执行时为旗标CREATE_SUSPENDED。线程将暂停直到呼叫ResumeThread来恢复线程的执行为止。第六个参数是一个指标,指向接受执行绪ID值的变量。

SetThreadAffinityMask:The SetThreadAffinityMask function sets a processor affinity mask for the specified thread.

DWORD_PTR SetThreadAffinityMask(HANDLE hThread, DWORD_PTR dwThreadAffinityMask);

调用SetThreadAffinityMask,能为各个线程设置亲缘性屏蔽:该函数中的h T h r e a d参数用于指明要限制哪个线程, dwThreadAffinityMask用于指明该线程能够在哪个CPU上运行。dwThreadAffinityMask必须是进程的亲缘性屏蔽的相应子集。返回值是线程的前一个亲缘性屏蔽。因此,若要将3个线程限制到CPU1、2和3上去运行,可以这样操作:

//Thread 0 can only run on CPU 0.

SetThreadAffinityMask(hThread0, 0x00000001); //第0位是1

//Threads 1, 2, 3 run on CPUs 1, 2, 3.//第1 2 3位是1

SetThreadAffinityMask(hThread1, 0x0000000E);

SetThreadAffinityMask(hThread2, 0x0000000E);

SetThreadAffinityMask(hThread3, 0x0000000E);

WaitForSingleObject 当指定的对象的状态被标记或者指定的时间间隔过完时,此函数返回DWORD类型参数。

格式:DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);

参数:hHandle表示对象的句柄,dwMilliseconds指出了时间间隔;过了指定的时间,即使对象状态没发生改变,函数也会返回;如果此参数设为0,函数测试对象的状态并且立即返回;如果此参数设为INFINITE,则表示此函数的时间间隔永远不会流逝完——只有等待对象状态被标识时返回。

返回值:成功:WAIT_OBJECT_0:表示对象的状态被标识

       WAIT_TIMEOUT:表示指定时间已到而对象状态没有被标识

    失败:WAIT_FAILED:表明失败

WaitForSingleObject 函数检查指定对象当前状态,如果对象的状态没有被标识,则调用的线程进入有效的等待状态。在等待对象状态被标识或者指定的时间间隔到期,线程只会占据(consume)处理器一小段时间。时间间隔需要被指定在0到0x7FFFFFFF之间的正数,最大的时间间隔值不等于无穷大而是0x7FFFFFFF,无穷大的时间间隔值是0xFFFFFFFF。任何在0x7FFFFFFF和0xFFFFFFFE之间的值都等同于0x7FFFFFFF;如果你需要一个时间间隔比0x7FFFFFFF还要大的话,使用表示不穷的值0xFFFFFFFF。返回之前,等待函数修改了某些类型的同步对象的状态,只有当对象的信号状态引起了函数的返回时这种修改才发生。例如,一个信号量对象计数减少1。WaitForSingleObject
函数能等待如下的各种对象:事件(Event)、线程(Thread)、进程(Process)、互斥量(Mutex)、信号量(Semaphore)。

使用时要小心调用等待函数和直接或间接产生窗口的代码。如果一个线程创建了窗口,那么它必须处理消息。广播消息发送到系统中的所有窗口。使用一个没有时间间隔的等待函数的线程可能导致系统死锁。例如,动态数据交换(DDE)协议和COM函数CoInitialize两个都间接地创建了可能导致死锁的窗口。因此,如果您有一个线程创建的窗口,使用MsgWaitForMultipleObjects 或者 MsgWaitForMultipleObjectsEx 而不是使用WaitForSingleObject。

======================================END===================================
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: