1、第四章 Windows多线程编程及调优,浙江大学计算机学院,Windows多线程API,在Windows平台下可以通过Windows的线程库来实现多线程编程提供的接口Win32 API或MFC.Net Framework实现方式的多样化给Windows编程带来了很大的灵活性也使得多线程编程变得复杂,Windows线程库,Win32 APIWindows操作系统为内核以及应用程序之间提供的接口将内核提供的功能进行函数封装应用程序通过调用相关的函数获得相应的系统功能。MFC微软基础函数类库(Microsoft Foundation Classes)用类库的方式将Win32 API 进行封装,以类的
2、方式提供.NETFramework构成公共语言运行库(CommonLanguageRuntime,CLR)文件加载器、垃圾收集器、安全系统Framework类库(FrameworkClassLibrary,FCL).NET 基础类库的System.Threading命名空间提供了大量的类和接口来支持多线程所有与多线程机制相关的类都存放在System.Threading命名空间中,使用win32线程API,Win32 函数库中提供了操作多线程的函数,包括创建线程、管理线程、终止线程、线程同步等接口。提供操作系统级别的创建线程的操作线程函数DWORD WINAPI ThreadFunc(LPVOI
3、D lpvThreadParm);线程创建HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);,第一个参数lpThreadAtt,是一个指向SECURITY-ATTRIBUTES结构的指针,该结构制定了线程的安全属性,缺省为 NULL。第二个参数dwStackSize,是栈的大小,一般设置为0
4、。第三个参数LPTHREAD_START_ROUTINE是新线程开始执行时,线程函数的入口地址。它必须是将要被新线程执行的函数地址,不能为NULL。lpStartAddress 参数指定了线程函数的地址,新建线程将从此地址开始执行,直到return语句返回,线程运行结束,把控制权交给操作系统。第四个参数lpParameter,是线程函数定义的参数。可以通过这个参数传送值,包括指针或者NULL。第五个参数dwCreationFlags,控制线程创建的附加标志,可以设置两种值。0表示线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,
5、并不马上执行,直至函数ResumeThread被调用;第六个参数lpThreadID,为指向32位变量的指针,该参数接受所创建线程的ID号。如果创建成功则返回线程的句柄,否则返回NULL。,_beginthread,创建线程还可以用process.h头文件中声明的C执行时期链接库函数_beginthread。在回调入口函数之前进行一些线程相关的CRT的初始化操作语法:hThread=_beginthread(void(_cdecl*start_address)(void*),unsigned stack_size,void*arglist);线程函数的语法:void _cdecl Thread
6、Proc(void*pParam);,使用_beginthread创建线程的例子,#include stdafx.h#include#include#include#include using namespace std;void ThreadFunc1(PVOID param)while(1)Sleep(1000);coutThis is ThreadFunc1endl;void ThreadFunc2(PVOID param)while(1),Sleep(1000);coutThis is ThreadFunc2endl;int main()int i=0;_beginthread(Thr
7、eadFunc1,0,NULL);_beginthread(ThreadFunc2,0,NULL);Sleep(3000);coutendendl;return 0;,线程管理,设置线程的优先级一个线程被创建时,它的优先级等于它所属进程的优先级SetThreadPriority函数设置线程的相对优先级Bool SetThreadPriority(HANDLE hPriority,int nPriority)线程与包含它的进程的优先级关系如下:线程优先级=进程优先级+线程相对优先级,设置线程的优先级,参数hPriority 是指向待设置的线程句柄进程的优先级包括:实时:REALTIME_PRIO
8、RITY_CLASS;高:HIGH _PRIORITY_CLASS;高于正常:ABOVE_NORMAL_PRIORITY_CLASS;正常:NORMAL _PRIORITY_CLASS;低于正常:BELOW_ NORMAL _PRIORITY_CLASS;空闲:IDLE_PRIORITY_CLASS。nPriority 是线程的相对优先级,可以是以下的值:最高线程:THREAD-PRIORITY-HIGHEST-2空闲:THREAD-PRIORITY-IDLE 15最低线程:THREAD-PRIORITY-LOWEST2低于正常线程:THREAD-PRIORITY-BELOW-NORMAL 1
9、正常线程:THREAD-PRIORITY-NORMAL 0高于正常线程:THREAD-PRIORITY-ABOVE NORMAL-1关键时间:THREAD-PRIORITY-TIME CRITICAL-15,线程的挂起与恢复,进程中的每个线程都有挂起计数器(suspend count)当挂起计数器值为0 时,线程被执行当挂起计数器值大于0 时,调度器不去调度该线程。不能够直接访问线程的挂起计数器 挂起 DWORD SuspendThread(HANDLE hThread);恢复 DWORD ResumeThread(HANDLE hThread);原型DWORD SuspendThread(H
10、ANDLE hThread);挂起指定的线程如果函数执行成功,则线程的执行被终止每次调用SuspendThread()函数,线程将挂起计数器的值增1 DWORD ResumeThread(HANDLE hThread);结束线程的挂起状态来执行这个线程每次调用ResumeThread()函数,线程将挂起计数器的值减1若挂起计数器的值为0,则不会再减,线程等待,一组能使线程阻塞其自身执行的等待函数WaitForSingleObjectWaitForMultipleObject在其参数中的一个或多个同步对象产生了信号,或者超过规定的等待时间才会返回在等待函数未返回时,线程处于等待状态,线程只消耗很
11、少的CPU时间,线程终结,在线程函数返回时,线程自动终止在线程的执行过程中终止则可调用函数:VOID ExitThread(DWORD dwExitCode);deallocate栈;取消I/O;结束线程如果在线程的外面终止线程,则可调用下面的函数:BOOL TerminateThread(HANDLE hThread,DWORDdw ExitCode);,Win32多线程的实现,下面这个程序首先创建两个线程,当输入为1时,执行线程,否则挂起线程。,#include#include using namespace std;DWORD WINAPI FunOne(LPVOID param)whi
12、le(true)Sleep(1000);couthello!;,return 0;DWORD WINAPI FunTwo(LPVOID param)while(true)Sleep(1000);coutworld!;return 0;,Win32多线程的实现(续),int main(int argc,char*argv)int input=0;HANDLE hand1=CreateThread(NULL,0,FunOne,(void*),线程执行和资源存取,线程之间通信的两个基本问题是互斥和同步线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程
13、的消息时应该等待,直到消息到达时才被唤醒。线程互斥是指对于共享资源,在各线程访问时的排它性线程互斥是一种特殊的线程同步 Win32线程同步的实现全局变量事件(Event)临界区(Critical section)互斥量(Mutex)信号量(Semaphore),Win32线程同步的实现-全局变量,全局变量进程中的所有线程均可以访问所有的全局变量,因而全局变量成为Win32多线程通信的最简单方式。int var;/全局变量UINT ThreadFunction(LPVOID pParam)while(var)/线程处理return 0;var是一个全局变量,任何线程均可以访问和修改。线程间可以利
14、用此特性达到线程同步的目的。,用全局变量同步线程的例子,#include#include using namespace std;int globalvar=false;DWORD WINAPI ThreadFunc(LPVOID pParam)coutThreadFuncendl;Sleep(200);globalvar=true;return 0;问题:主线程等待globalvar为真,如不为真则一直循环,这样占用了CPU资源如果主线程优先级高于ThreadFunc,则globalvar一直不会被置为真,int main()HANDLE hthread=CreateThread(NULL,
15、0,ThreadFunc,NULL,0,NULL);if(!hthread)coutThread Create Error!endl;CloseHandle(hthread);while(!globalvar)coutThread whileendl;coutThread exitendl;return 0;,事件,事件(Event)是WIN32提供的最灵活的线程间同步方式用来发送命令或触发事件,安排事件执行的先后次序事件存在两种状态:激发状态(signaled or true)未激发状态(unsignal or false)事件可分为两类:手动设置这种对象只能用程序来手动设置,在需要该事件或
16、者事件发生时,采用SetEvent及ResetEvent来进行设置。自动恢复一旦事件发生并被处理后,自动恢复到没有事件状态,不需要再次设置。手动重置事件被设置为激发状态后,会唤醒所有等待的线程,而且一直保持为激发状态,直到程序重新把它设置为未激发状态。自动重置事件被设置为激发状态后,会唤醒“一个”等待中的线程,然后自动恢复为未激发状态,原型为:HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,BOOL bInitialState,LPCTSTR lpName);其中:第一个参数:与CreateThread中的第一个参数类似,是一个指向SECURITY-ATTRIBUTES结构的指针第二个参数:代表事件的类型,是手动清除事件信号还是自动清除事件信号。TRUE为手动清除。第三个参数:指明事件的初始状态第四个参数:事件的名称,使用“事件”机制注意事项,(1)设置事件是否要自动恢复;(2)设置事件的初始状态;(3)如果跨进程访问事件,必须对事件命名,在对事件命名的时候,要注意不要与系统命名空
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1