




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第二章 Windows多线程编程内容1. Windows操作系统的一些基本知识操作系统的一些基本知识 2. Win32 API线程库线程库 3. 线程间通信线程间通信 1、Windows操作系统的一些基本知识操作系统的一些基本知识 1. API2. 内核对象及句柄内核对象及句柄API ( Application Programming Interface )nAPIAPI:操作系统留给应用程序的一个调用接口,操作系统留给应用程序的一个调用接口,应用程序通过应用程序通过APIAPI使操作系统去执行使操作系统去执行相应相应程序程序。nWindows APIWindows API是一套用来控制是一套
2、用来控制WindowsWindows的各个部件的各个部件的外观和行为的预先定义的的外观和行为的预先定义的WindowsWindows函数。函数。nWin32 APIWin32 API即为即为Microsoft 32Microsoft 32位平台的应用程序位平台的应用程序编程接口。编程接口。Win32Win32平台上运行的应用程序都可以平台上运行的应用程序都可以调用这些函数。调用这些函数。n3232与与6464位位APIAPI函数声明上没有明显区别,但函数声明上没有明显区别,但6464位位编程是需要下载相应的编程是需要下载相应的软件开发包软件开发包SDKSDK。 API ( Applicatio
3、n Programming Interface )n直接用直接用win32 APIwin32 API编写的应用程序,程序的执行编写的应用程序,程序的执行代码小,运行效率高代码小,运行效率高nMFCMFC用类库的方式将用类库的方式将 win32 API win32 API 进行封装进行封装, , 以类以类的方式提供给开发者的方式提供给开发者内核对象及句柄n内核对象是由操作系统内核分配,内核对象是由操作系统内核分配,只能由内核访只能由内核访问的数据结构问的数据结构,供系统和应用程序使用来管理各供系统和应用程序使用来管理各种系统资源种系统资源 。n内核对象包括:内核对象包括:进程对象、线程对象、事件
4、对象、进程对象、线程对象、事件对象、文件对象、作业对象、互斥对象、等待计时器对文件对象、作业对象、互斥对象、等待计时器对象等都是内核对象。象等都是内核对象。n出于安全的考虑,进程不能直接访问内核对象。出于安全的考虑,进程不能直接访问内核对象。n操作系统提供了一组函数来访问内核对象。通过操作系统提供了一组函数来访问内核对象。通过函数创建、打开和操作内核对象。函数创建、打开和操作内核对象。内核对象及句柄n内核对象由内核拥有,各个进程可以共享内核对内核对象由内核拥有,各个进程可以共享内核对象。进程终止执行,它使用的内核对象并不一定象。进程终止执行,它使用的内核对象并不一定会被撤销。会被撤销。n每个内
5、核对象都有一个计数器来存储有多少个进每个内核对象都有一个计数器来存储有多少个进程在使用它的信息。程在使用它的信息。n进程调用时,计数器增进程调用时,计数器增1,调用结束,计数器减,调用结束,计数器减1。n内核对象计数器为零时,销毁此内核对象。内核对象计数器为零时,销毁此内核对象。 内核对象及句柄n内核对象有安全描述符的保护,安全描述符描述内核对象有安全描述符的保护,安全描述符描述了谁创建了该对象以及谁能够使用该对象。了谁创建了该对象以及谁能够使用该对象。n用于创建内核对象的函数几乎都有一个指向用于创建内核对象的函数几乎都有一个指向SECURITY_ATTRIBUTES 结构的指针作为其参结构的
6、指针作为其参数。数。n 大多数应用程序通过传大多数应用程序通过传NULL值,创建具有默认值,创建具有默认安全性的对象。如果想限制其他线程对对象的访安全性的对象。如果想限制其他线程对对象的访问,就需要单独创建一个问,就需要单独创建一个SECURITY_ATTRIBUTES对象并对其初始化。对象并对其初始化。内核对象及句柄n句柄:句柄:创建内核对象时,函数的返回值,标记该创建内核对象时,函数的返回值,标记该内核对象。内核对象。n句柄表:句柄表:进程被初始化时,系统给进程分配一个进程被初始化时,系统给进程分配一个句柄表,用于保存该进程使用的内核对象的信息,句柄表,用于保存该进程使用的内核对象的信息,
7、而句柄值则是相应内核对象在句柄表中的索引值,而句柄值则是相应内核对象在句柄表中的索引值,因此句柄值是进程相关的。因此句柄值是进程相关的。内核对象及句柄n内核对象创建内核对象创建n当利用当利用creat*函数来创建内核对象时,系统内核就为该函数来创建内核对象时,系统内核就为该对象分配一个内存块,并进行初始化,然后系统内核扫对象分配一个内存块,并进行初始化,然后系统内核扫描该进程的句柄表,初始化一条记录并放在句柄表中。描该进程的句柄表,初始化一条记录并放在句柄表中。n关闭内核对象关闭内核对象n无论进程怎样创建内核对象,在不使用该对象的时候都无论进程怎样创建内核对象,在不使用该对象的时候都应当通过应
8、当通过Bool CloseHandle(HANDLE hobj)来向操作来向操作统声明结束对该对象的访问。统声明结束对该对象的访问。Win32 API线程库线程库 1. 创建线程的基本问题创建线程的基本问题2. 创建线程的创建线程的API函数函数3. 操作线程的操作线程的API4. 一个简单的一个简单的Windows多线程程序多线程程序1 创建线程的基本问题 n线程可以由进程中的任意线程创建,而进程的主线程在进线程可以由进程中的任意线程创建,而进程的主线程在进程加载时自动创建。程加载时自动创建。n每个线程都有自己的进入点函数。每个线程都有自己的进入点函数。n主线程的进入点函数主线程的进入点函数
9、进入点进入点应用程序类型应用程序类型WinMainWinMain需要需要ANSIANSI字符和字符串的字符和字符串的GUIGUI应用程序应用程序wWinMainwWinMain需要需要UnicodeUnicode字符和字符串的字符和字符串的GUIGUI应用程序应用程序MainMain需要需要ANSIANSI字符和字符串的字符和字符串的CUICUI应用程序应用程序WmainWmain需要需要UnicodeUnicode字符和字符串的字符和字符串的CUICUI应用程序应用程序 线程函数的返回值是该线程的退出代码线程函数的返回值是该线程的退出代码 线程函数应尽可能使用函数参数和局部变量线程函数应尽可
10、能使用函数参数和局部变量线程函数-线程的入口点DWORD WINAPI ThreadFunc ( PVOID pvParam ) DWORD dwResult = 0;return (dwResult);2 创建线程的API函数n创建线程过程:创建线程过程:n系统创建一个线程内核对象。线程内核对象不系统创建一个线程内核对象。线程内核对象不是线程本身,而是操作系统用来管理线程的较是线程本身,而是操作系统用来管理线程的较小的数据结构。小的数据结构。n在进程的地址空间分配内存,供线程的堆栈使在进程的地址空间分配内存,供线程的堆栈使用用HANDLE CreateThread(PSECURITY_ATT
11、RIBUTES psa, DWORD cbStack,PTHREAD_START_ROUTINE pStartAddr,PVOID pvParam, DWORD fdwCreate, PDWORD pdwThreadId); 2 创建线程的API函数NULL0函数地址函数地址函数参数函数参数NULL控制创建线程标志控制创建线程标志CREATE_SUSPENDED0线程线程ID#include windows.h#include using namespace std;DWORD WINAPI ThreadFunc(PVOID pvParam)coutCreated thread says he
12、llo World!endl;return 0;int main()HANDLE ThreadHandle = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);Sleep(100);coutMain thread says Hello World!endl;getchar();return 0;n暂停线程暂停线程DWORD DWORD SuspendThread(HANDLESuspendThread(HANDLE hThreadhThread) )n返回值是线程的前一个暂停计数返回值是线程的前一个暂停计数n暂停计数:是线程内核对象的一个内部值。暂停计数
13、:是线程内核对象的一个内部值。n使用要小心,因为不知道暂停线程运行时它在进使用要小心,因为不知道暂停线程运行时它在进行什么操作。可能造成死锁行什么操作。可能造成死锁3 操作线程的API3 操作线程的APIn恢复线程恢复线程DWORD DWORD ResumeThread(HANDLEResumeThread(HANDLE hThreadhThread); ); n返回值是线程的前一个暂停计数返回值是线程的前一个暂停计数n该函数用于将处于暂停状态的线程置于就该函数用于将处于暂停状态的线程置于就绪状态,使其参加线程调度。绪状态,使其参加线程调度。3 操作线程的APIn使线程睡眠使线程睡眠VOID
14、Sleep (DWORD VOID Sleep (DWORD dwMillisecondsdwMilliseconds ); );n该函数是线程暂停自己的运行,直到睡眠时间过该函数是线程暂停自己的运行,直到睡眠时间过去为止。去为止。n当线程调用这个函数时,它自动放弃剩余的时间当线程调用这个函数时,它自动放弃剩余的时间片,迫使系统进行线程调度。片,迫使系统进行线程调度。nWindowsWindows不是实时的操作系统。不是实时的操作系统。3 操作线程的APIn终止线程终止线程 线程函数返回(最好)线程函数返回(最好) 通过调用通过调用ExitThreadExitThread函数,线程将自行撤销函
15、数,线程将自行撤销 同一个进程或另一个进程中的线程调用同一个进程或另一个进程中的线程调用TerminateThreadTerminateThread函数函数 包含线程的进程终止包含线程的进程终止 线程返回函数线程返回函数n线程中创建的线程中创建的C+C+类对象能够正常撤销;类对象能够正常撤销;n操作系统将正确地释放线程堆栈使用的内操作系统将正确地释放线程堆栈使用的内存;存;n系统将线程的退出代码设置为线程函数的系统将线程的退出代码设置为线程函数的返回值;返回值;n系统将递减线程内核对象的使用计数。系统将递减线程内核对象的使用计数。n线程调用这个函数,强制线程终止运行;线程调用这个函数,强制线程
16、终止运行;n操作系统清除该线程使用的所有系统资源。操作系统清除该线程使用的所有系统资源。nC+C+类对象将不被撤销。类对象将不被撤销。VOID VOID ExitThread(DWORDExitThread(DWORD dwExitCodedwExitCode); ); ExitThreadExitThread函数函数n能够撤销任何线程;能够撤销任何线程;n线程的内核对象的使用计数也被递减;线程的内核对象的使用计数也被递减;n异步运行的函数;异步运行的函数;n不撤销线程的堆栈,直到进程终止。不撤销线程的堆栈,直到进程终止。BOOL BOOL TerminateThread(HANDLETerm
17、inateThread(HANDLE hThread,DWORDhThread,DWORD dwExitCodedwExitCode); ); TerminateThreadTerminateThread函数函数 在进程终止运行时撤销线程nExitProcessExitProcess 和和 TerminateProcessTerminateProcess函数可以终止线程,函数可以终止线程,将会终止进程中的所有线程;将会终止进程中的所有线程;nExitProcessExitProcess只能强制执行本进程的退出;只能强制执行本进程的退出;nTerminateProcessTerminatePro
18、cess在一个进程中强制结束其他的进程;在一个进程中强制结束其他的进程; n进程所使用的资源被清除;进程所使用的资源被清除;nC+C+对象撤销函数没有被调用。对象撤销函数没有被调用。VOID VOID ExitProcess(UINTExitProcess(UINT uExitCodeuExitCode); ); BOOL BOOL TerminateProcess(HANDLETerminateProcess(HANDLE hProcesshProcess, UINT , UINT uExitCodeuExitCode); ); #include #include using namespa
19、ce std;DWORD WINAPI FunOne(LPVOID param)int* p=(int*)param;cout(*p)endl; while(true) Sleep(1000); couthello! ; return 0; DWORD WINAPI FunTwo(LPVOID param)int* p=(int*)param;cout(*p)endl; while(true) Sleep(1000); coutinput; if(input=1) ResumeThread(hand1);ResumeThread(hand2); else SuspendThread(hand1
20、);SuspendThread(hand2); TerminateThread(hand1,1); TerminateThread(hand2,1); return 0;例例n打印出打印出1001000之间的所有之间的所有“水仙花数水仙花数”,所谓,所谓“水仙花数水仙花数”是指一个三位数,其是指一个三位数,其各位数字立方和等于该数本身。各位数字立方和等于该数本身。n例如:例如:153是一个是一个“水仙花数水仙花数”,因为,因为153=13+33+53n不需要通信不需要通信int main( )int i,j,k,n;printf(水仙花数水仙花数是是:);for(n=100;nlow;int
21、high = bou-high;for(n=low;nhigh;n+)i=n/100;j=n/10-i*10;k=n%10;if(i*100+j*10+k=i*i*i+j*j*j+k*k*k)printf(%d ,n);return 0;int main( )printf(水仙花数水仙花数是是:);bound qw1,qw2;qw1.low=100;qw1.high =500; HANDLE ThreadHandle1= CreateThread(NULL,0,Thread1,&qw1,0,NULL);qw2.low=500;qw2.high=1000;HANDLE ThreadHan
22、dle2 = CreateThread(NULL,0,Thread1,&qw2,0,NULL);HANDLE ThreadHandles2= ThreadHandle1,ThreadHandle2;WaitForMultipleObjects(2,ThreadHandles,TRUE,INFINITE);return 0;线程间通信n操作系统随机调度线程,程序员不能预知线程的执行顺序操作系统随机调度线程,程序员不能预知线程的执行顺序n下面两种情况下,线程间需要通信下面两种情况下,线程间需要通信n当有多个线程访问共享资源而不希望共享资源遭到破当有多个线程访问共享资源而不希望共享资源遭到破
23、坏;(互斥)坏;(互斥)n当一个线程需要将某个任务已经完成的情况通知另外当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程时。(同步)一个或多个线程时。(同步)nWindowsWindows线程通信方法主要有互锁函数、临界段、线程通信方法主要有互锁函数、临界段、事件、事件、互斥量、信号量互斥量、信号量线程间通信1.1.互锁函数互锁函数2.2.临界段临界段3.3.事件事件4.4.互斥量互斥量5.5.信号量信号量使用内核对象的线程间通信n互锁函数和临界段都是在用户态实现线程通信的,互锁函数和临界段都是在用户态实现线程通信的,优点速度快优点速度快n用户态机制只能实现同一进程内线程通信。用户
24、态机制只能实现同一进程内线程通信。n内核对象机制可以实现不同进程内线程的通信,缺内核对象机制可以实现不同进程内线程的通信,缺点速度慢。点速度慢。n包含通知状态和未通知状态内核属性包含通知状态和未通知状态内核属性的内核对象有:的内核对象有:n进程,线程进程,线程,作业,文件,控制台输入,作业,文件,控制台输入n文件修改通知,事件,可等待定时器文件修改通知,事件,可等待定时器n信号量,互斥量信号量,互斥量n等待函数:使线程进入等待状态等待函数:使线程进入等待状态, ,直到一直到一个对象变为已通知状态。个对象变为已通知状态。DWORD WaitForSingleObject( HANDLE hHan
25、dle, DWORD dwMilliseconds ); 参数参数dwMillisecondsdwMilliseconds有两个特殊值:有两个特殊值:0 0,则该函数立即返回;,则该函数立即返回;INFINITEINFINITE,则线程被挂起,直到,则线程被挂起,直到hHandlehHandle所指向的对所指向的对象变为已通知状态。象变为已通知状态。 使用内核对象的线程间通信n等待函数:等待函数:可以保证线程的同步可以保证线程的同步 。DWORD WaitForMultipleObject( DWORD dwCount,CONST HANDLE* phHandle, BOOL fWaitAll
26、,DWORD dwMilliseconds ); 使用内核对象的线程间通信1、互锁函数n互锁函数是用来解决原子访问的,主要针对变量互锁函数是用来解决原子访问的,主要针对变量的原子访问;的原子访问;n原子访问:当线程访问资源时,能够确保没有其原子访问:当线程访问资源时,能够确保没有其它线程同时访问相同的资源。它线程同时访问相同的资源。Long g_x = 0; /全局变量全局变量DWORD WINAPI ThreadFunc1 (PVOID pvParam) g_x+;return 0; DWORD WINAPI ThreadFunc2 (PVOID pvParam) g_x+;return 0
27、; MOV EAX, g_xINC EAXMOV g_x, EAX递增以原子方式运行递增以原子方式运行1、互锁函数(例)1、互锁函数LONG InterlockedExchangeAdd()( PLONG plAddend, LONG lIncrement);Long g_x=0; /全局变量全局变量DWORD WINAPI ThreadFunc1 (PVOID pvParam) InterlockedExchangeAdd(&g_x,1);return 0; DWORD WINAPI ThreadFunc2 (PVOID pvParam) InterlockedExchangeAdd
28、(&g_x,1);return 0; 1、互锁函数n以原子操作方式用第二个参数的值取代第以原子操作方式用第二个参数的值取代第一个参数的当前值。一个参数的当前值。LONG InterlockedExchange ()( PLONG plTarget, LONG lValue);LONG InterlockedExchangePointer ()( PVOID* ppvTarget, PVOID pvValue);1、互锁函数n比较第一个参数所指的值和第三个参数的值,如比较第一个参数所指的值和第三个参数的值,如果相等,则将第一个参数所指的值置为第二个参果相等,则将第一个参数所指的值置为第二
29、个参数,如果不相等则不进行任何操作。数,如果不相等则不进行任何操作。LONG LONG InterlockedCompareExchangeInterlockedCompareExchange ()( ()( PLONG PLONG plDestinationplDestination, LONG , LONG lExchangelExchange, LONG , LONG lComparandlComparand););LONG LONG InterlockedCompareExchangePointerInterlockedCompareExchangePointer ()( ()( PV
30、OID PVOID* * ppvDestinationppvDestination, PVOID , PVOID pvExchangepvExchange, PVOID , PVOID pvComparandpvComparand););例:例:10000个个2相加相加int main( )int sum=0;for(int i=1;i=10000; i+)sum=sum+2;printf(10000个个2相加之和是相加之和是 %d,sum);getchar();return 0;#include windows.hlong sum=0;DWORD WINAPI Thread1(PVOID p
31、vParam)for(int i=1;i=5000; i+)/InterlockedExchangeAdd(&sum,2);sum=sum+2;return 0;DWORD WINAPI Thread2(PVOID pvParam)for(int i=5001;i=10000; i+)/InterlockedExchangeAdd(&sum,2);sum=sum+2;return 0;int main()HANDLE ThreadHandle1 = CreateThread(NULL,0,Thread1,NULL,0,NULL);HANDLE ThreadHandle2 = C
32、reateThread(NULL,0,Thread2,NULL,0,NULL);HANDLE ThreadHandles2= ThreadHandle1,ThreadHandle2;WaitForMultipleObjects(2,ThreadHandles,TRUE,INFINITE);printf(10000个个2相加之和是相加之和是 %d,sum);getchar();return 0;2、临界段n互锁函数:以原子操作方式修改单个值互锁函数:以原子操作方式修改单个值n临界段:以原子方式修改复杂的数据结构。临界段:以原子方式修改复杂的数据结构。n临界段:关键代码段,是指一小段代码,同临界段
33、:关键代码段,是指一小段代码,同一个时刻,只能有一个线程具有访问权。一个时刻,只能有一个线程具有访问权。n多个线程访问同一个临界区的原则:多个线程访问同一个临界区的原则:n 一次最多只能一个线程停留在临界区内;一次最多只能一个线程停留在临界区内;n 不能让一个线程无限地停留在临界区内,否则不能让一个线程无限地停留在临界区内,否则其它线程将不能进入该临界区其它线程将不能进入该临界区 2、临界段 相关API函数 n首先定义一个临界段对象(通常全局变量)首先定义一个临界段对象(通常全局变量)CRITICAL_SECTION CRITICAL_SECTION cscsn临界段对象初始化临界段对象初始化
34、InitializeCriticalSectionInitializeCriticalSection (& (&cscs)n进入临界段进入临界段EnterCriticalSectionEnterCriticalSection (& (&cscs) )n离开临界段离开临界段LeaveCriticalSectionLeaveCriticalSection (& (&cscs) )n释放临界段对象释放临界段对象DeleteCriticalSectionDeleteCriticalSection (& (&cscs) )临界段 例1#in
35、clude #include fstream file;DWORD WINAPI ThreadFunc1(PVOID param)for(int i=1;i=1000;i+)fileThreadFunc1 Outputiendl;return 0;DWORD WINAPI ThreadFunc2(PVOID param) for(int i=1;i=1000;i+)fileThreadFunc2 Outputiendl;return 0;int main() file.open(data.txt,ios:out);HANDLE ThreadHandle1 = CreateThread(NULL
36、,0,ThreadFunc1,NULL,0,NULL);HANDLE ThreadHandle2 = CreateThread(NULL,0,ThreadFunc2,NULL,0,NULL);HANDLE hThread2 = ThreadHandle1,ThreadHandle2;WaitForMultipleObjects(2,hThread,TRUE,INFINITE);file.close();return 0;加上临界段#include #include fstream file;CRITICAL_SECTION cs;DWORD WINAPI ThreadFunc1(PVOID p
37、aram)for(int i=1;i=1000;i+)EnterCriticalSection (&cs);fileThreadFunc1 Outputiendl;LeaveCriticalSection (&cs);return 0;DWORD WINAPI ThreadFunc2(PVOID param) for(int i=1;i=1000;i+)EnterCriticalSection (&cs);fileThreadFunc2 Outputiendl;LeaveCriticalSection (&cs);return 0;#include “windo
38、ws.h“ 例例2CRITICAL_SECTION g_cs;char g_cArray10; / 共享资源共享资源 DWORD WINAPI ThreadProc1(PVOID pParam)EnterCriticalSection(&g_cs);/ 对共享资源进行写入操作对共享资源进行写入操作for (int i = 0; i 10; i+)g_cArrayi = a;Sleep(1);LeaveCriticalSection(&g_cs);return 0;DWORD WINAPI ThreadProc2(PVOID pParam)/ 进入临界区进入临界区EnterCri
39、ticalSection(&g_cs);/ 对共享资源进行写入操作对共享资源进行写入操作for (int i = 0; i 10; i+)g_cArray10 - i - 1 = b;Sleep(1);/ 离开临界区离开临界区LeaveCriticalSection(&g_cs);return 0;int main()InitializeCriticalSection(&g_cs);HANDLE ThreadHandle1 = CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);HANDLE ThreadHandle2 = Crea
40、teThread(NULL,0,ThreadProc2,NULL,0,NULL);HANDLE ThreadHandles2= ThreadHandle1,ThreadHandle2;WaitForMultipleObjects(2,ThreadHandles,TRUE,INFINITE);DeleteCriticalSection(&g_cs);printf(g_cArray);getchar();return 0;3、事件n事件内核对象是最简单的对象。事件内核对象是最简单的对象。n一个使用计数一个使用计数n一个布尔值,指明该事件是自动复位事件一个布尔值,指明该事件是自动复位事件(f
41、alse)(false),还是人工复位事件,还是人工复位事件(true)(true);n一个布尔值,指明该事件是已通知状态一个布尔值,指明该事件是已通知状态(true)(true),还是未通知状态还是未通知状态(false)(false) 。 n当人工复位事件得到通知时,等待该事件的所有当人工复位事件得到通知时,等待该事件的所有线程均变为可调度事件;线程均变为可调度事件;n当自动复位事件得到通知时,等待该事件的线程当自动复位事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。中只有一个线程变为可调度线程。 n创建事件内核对象,返回句柄。创建事件内核对象,返回句柄。 HANDLE HA
42、NDLE CreateEventCreateEvent( ( PSECURITY_ATTRIBUTES PSECURITY_ATTRIBUTES psapsa, / , / 安全属性安全属性 BOOL BOOL fManualResetfManualReset, /, /复位方式复位方式 BOOL BOOL fInitialStatefInitialState, / , / 初始状态初始状态 PCTSTR PCTSTR pszNamepszName / / 对象名称对象名称 ); ); 3、事件n打开一个已经存在的命名事件对象打开一个已经存在的命名事件对象 HANDLE HANDLE Open
43、EventOpenEvent( ( DWORD DWORD f fdwAccessdwAccess, , BOOL BOOL f fInheritInherit, , PCTSTR PCTSTR pszpszNameName ); ); 3、事件EVENT_ALL_ACCESS 要求对事件对象进行完全访问EVENT_MODIFY_STATE 允许SetEvent 和 ResetEvent函数SYNCHRONIZE 允许事件对象的使用同步 n一旦事件已经创建,就可以直接控制它的状态一旦事件已经创建,就可以直接控制它的状态n将事件设置为已通知状态将事件设置为已通知状态BOOL BOOL SetEv
44、ent(HANDLESetEvent(HANDLE hEventhEvent ); ); n将事件设置为未通知状态将事件设置为未通知状态BOOL BOOL ResetEvent(HANDLEResetEvent(HANDLE hEventhEvent ); );3、事件3、事件n事件的主要用途是标志事件的发生,并以事件的主要用途是标志事件的发生,并以此协调线程的执行顺序。此协调线程的执行顺序。n例例1:用户在主线程输入命令,控制新建线:用户在主线程输入命令,控制新建线程的运行。程的运行。#include #include #include using namespace std;CRITICA
45、L_SECTION cs;DWORD WINAPI ThreadFunc(PVOID param) EnterCriticalSection (&cs); coutCreate Thread: Create thread is startedendl; coutCreate Thread: Create thread is waiting continue command.endl; LeaveCriticalSection (&cs); HANDLE phEvent = OpenEvent(EVENT_ALL_ACCESS,TRUE,ContinueCommand); Wai
46、tForSingleObject(phEvent,INFINITE); coutCreate Thread: Recieved continue command.endl; coutCreate Thread: Thread runs again.endl; Sleep(2000); coutCreate Thread: Thread finished.endl; return 0;例例1int main()InitializeCriticalSection (&cs);HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,ContinueComma
47、nd);coutMain Thread: Creating new thread.endl;HANDLE ThreadHandle = CreateThread(NULL,0,ThreadFunc,NULL,CREATE_SUSPENDED,NULL);coutMain Thread: New thread created.endl;ResumeThread(ThreadHandle);string input;while(TRUE)EnterCriticalSection (&cs);coutMain Thread: input command, pleaseendl;LeaveCr
48、iticalSection (&cs);cout;cininput;if(input=continue)coutMain Thread: Let thread continue runendl;SetEvent(hEvent);break;WaitForSingleObject(ThreadHandle,INFINITE);coutMain Thread: Create thread finishedendl;DeleteCriticalSection (&cs);CloseHandle(hEvent);return 0;例2n设计简单的文字管理软件,要求实现功能设计简单的文字
49、管理软件,要求实现功能,读文件、字数统计、拼写检查、语法检,读文件、字数统计、拼写检查、语法检查查#include HANDLE g_hEvent; void OpenFileAndReadContentsIntoMemory() printf(Open File and Read contents into memoryn);DWORD WINAPI WordCount(PVOID pvParam) WaitForSingleObject(g_hEvent, INFINITE); printf(0:word countn); SetEvent(g_hEvent); /自动自动 return(
50、0);DWORD WINAPI SpellCheck(PVOID pvParam) WaitForSingleObject(g_hEvent, INFINITE); printf(1:Spell checkn); /Access the memory block. SetEvent(g_hEvent); /自动自动 return(0);DWORD WINAPI GrammarCheck(PVOID pvParam) WaitForSingleObject(g_hEvent, INFINITE); printf(2:Grammar checkn); /Access the memory bloc
51、k. SetEvent(g_hEvent); /自动自动 return(0);int main()/ g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /人工重置人工重置 g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); /自动重置自动重置 HANDLE hThread3; DWORD dwThreadID3; hThread0 = CreateThread(NULL, 0, WordCount, NULL, 0, &dwThreadID0); hThread1 = CreateThrea
52、d(NULL, 0, SpellCheck, NULL, 0, &dwThreadID1); hThread2 = CreateThread(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID2); OpenFileAndReadContentsIntoMemory(); /Allow all 3 threads to access the memory. SetEvent(g_hEvent); WaitForMultipleObjects (3, hThread, TRUE, INFINITE); printf(main thread ex
53、itn); getchar(); return 0;例3:协调两个线程执行顺序n读操作、写操作读操作、写操作n先写后读先写后读HANDLE evRead, evFinish;DWORD WINAPI ReadThread(PVOID param)WaitForSingleObject (evRead ,INFINITE);coutReadingendl;SetEvent (evFinish);DWORD WINAPI WriteThread(PVOID param)coutWritingendl;SetEvent (evRead);int main()evRead = CreateEvent
54、(NULL ,FALSE ,FALSE ,NULL) ;evFinish = CreateEvent (NULL ,FALSE ,FALSE ,NULL) ; CreateThread(NULL,0, ReadThread,NULL,0,NULL); CreateThread(NULL,0, WriteThread,NULL,0,NULL);WaitForSingleObject (evFinish,INFINITE) ;coutThe Program is Endendl;return 0 ;4、互斥量n互斥量是一个种内核对象,确保线程拥有对互斥量是一个种内核对象,确保线程拥有对单个资源的互
55、斥访问权。单个资源的互斥访问权。n一个使用数量一个使用数量n一个线程一个线程IDn一个递归计数器一个递归计数器n互斥量的线程互斥量的线程ID标识系统中哪个线程拥有互标识系统中哪个线程拥有互斥量,为斥量,为0,没有线程拥有,没有线程拥有n递归计数器指明线程拥有互斥量的次数递归计数器指明线程拥有互斥量的次数4、互斥量n经常用于保护多个线程访问的内存块;经常用于保护多个线程访问的内存块;n控制对共享资源的访问控制对共享资源的访问 n保证每次只能有一个线程获得互斥量保证每次只能有一个线程获得互斥量 4、互斥量n互斥量的创建,返回句柄互斥量的创建,返回句柄 HANDLE CreateMutex( PSE
56、CURITY_ATTRIBUTES psa, / 安全属性的指针安全属性的指针 BOOL bInitialOwner, / 初始化互斥对象的所有者初始化互斥对象的所有者 PCTSTR pszName / 指向互斥对象名的指针指向互斥对象名的指针 ); InitialOwner:FALSE,互斥对象的线程ID和递归计数器均被设置为0。TRUE,互斥对象的线程ID被设置为调用线程的ID,递归计数器被设置为1。4、互斥量n为现有的一个已命名互斥对象创建一个新句柄为现有的一个已命名互斥对象创建一个新句柄 HANDLE OpenMutex( DWORD fdwAccess, / access BOOL
57、bInheritHandle, / inheritance option PCTSTR pszName / object name ); MUTEX_ALL_ACCESS 请求对互斥对象的完全访问MUTEX_MODIFY_STATE 允许使用 ReleaseMutex 函数SYNCHRONIZE 允许使用互斥对象同步n释放互斥量释放互斥量 HANDLE HANDLE ReleaseMutexReleaseMutex( ( HANDLE HANDLE hMutexhMutex); ); n等待互斥量等待互斥量DWORD DWORD WaitForSingleObjectWaitForSingle
58、Object( ( HANDLE HANDLE hHandlehHandle, , DWORD DWORD dwMillisecondsdwMilliseconds ););n互斥量不同于其它内核对象,互斥对象有一个互斥量不同于其它内核对象,互斥对象有一个“线程所有线程所有权权”的概念。的概念。4、互斥量#include #include using namespace std;fstream file;DWORD WINAPI ThreadFunc1(PVOID param)HANDLE *phMutex=(HANDLE *)param;for(int i=1;i=100;i+)WaitFo
59、rSingleObject(*phMutex,INFINITE);fileThreadFunc1 Outputiendl;ReleaseMutex(*phMutex); return 0;例例1DWORD WINAPI ThreadFunc2(PVOID param) HANDLE *phMutex=(HANDLE *)param;for(int i=1;i=100;i+)WaitForSingleObject(*phMutex,INFINITE);fileThreadFunc2 Outputiendl;ReleaseMutex(*phMutex); return 0;int main()fi
60、le.open(data.txt,ios:out);HANDLE hMutex = CreateMutex(NULL,FALSE,DisplayMutex);HANDLE ThreadHandle1 = CreateThread(NULL,0,ThreadFunc1,&hMutex,0,NULL);HANDLE ThreadHandle2 = CreateThread(NULL,0,ThreadFunc2,&hMutex,0,NULL);HANDLE hThread2 = ThreadHandle1,ThreadHandle2;WaitForMultipleObjects(2,hThread,TRUE,INFINITE);CloseHandle(hMutex);file.close();return 0;比较临界区、互斥量、事件n给数组元素赋值,并在屏幕打印出来给数组元素赋值,并在屏幕打印出来n改变起始值,无限重复上述过程改变起始值,无限重复上述过程#incl
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 电商内容营销自动化工具创新创业项目商业计划书
- 农畜产品天然成分提取创新创业项目商业计划书
- 农产品产地直销网络创新创业项目商业计划书
- 2025年学前教育机构师资队伍教师培训效果评价与反馈体系报告
- 2025年工业互联网平台NFV虚拟化在5G网络中的应用场景报告
- 2025年工业节能技术改造资金申请项目申报条件与评估报告
- 2025年教育行业人才流失现状与吸引力建设策略报告
- 2025年网络直播行业规范化与直播平台国际化发展商业模式创新报告
- 甘肃省定西市岷县2021-2022学年第一学期五年级科学期中试题(含答案)
- 营养师考试2025年备考实操技能与营养调查模拟试卷
- 2025护理文书书写规范
- 2025年机械设计与制造考试试题及答案
- 大数据风控与信用评估体系
- 新媒体运营学习心得体会
- DB32T 5124.2-2025 临床护理技术规范 第2部分:成人危重症患者无创腹内压监测
- 可信数据空间解决方案星环科技
- Part3-4 Unit1 Travel 课件-【中职专用】高一英语(高教版2021基础模块2)(2023修订版)
- 中学班级文化建设实施方案
- 2025年中学教师资格考试《综合素质》核心考点特训题库(含答案)之教育管理论述题
- 全球重要农业文化遗产申报路径
- 公司政治监督工作方案
评论
0/150
提交评论