化工大学Windows多线程编程_第1页
化工大学Windows多线程编程_第2页
化工大学Windows多线程编程_第3页
化工大学Windows多线程编程_第4页
化工大学Windows多线程编程_第5页
已阅读5页,还剩67页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第二章Windows多线程编程内容Windows操作系统的一些基本知识Win32API线程库线程间通信1、Windows操作系统的一些基本知识API内核对象及句柄API(ApplicationProgrammingInterface)API操作系统留给应用程序的一个调用接口,应用程序通过调用操作系统的API而使操作系统去执行应用程序的命令(动作)。WindowsAPI是一套用来控制Windows的各个部件的外观和行为的预先定义的Windows函数。Win32API即为Microsoft32位平台的应用程序编程接口。Win32平台上运行的应用程序都可以调用这些函数。32与64位API函数声明上没有明显区别,但64位编程是需要下载相应的平台SDK

API(ApplicationProgrammingInterface)直接用win32API编写的应用程序,程序的执行代码小,运行效率高MFC用类库的方式将win32API进行封装,以类的方式提供给开发者Framework类库提供了所有应用程序模型都要使用的一个面向对象的API集合内核对象及句柄当应用程序要与系统设备进行交互的时候,将使用到内核对象。出于安全的考虑,进程是不能直接访问内核对象的,操作系统提供了对应的函数来对它们进行访问。内核对象是由操作系统内核分配,只能由内核访问的数据结构,用来管理各种系统资源。内核对象包括:存取符号对象、事件对象、文件对象、作业对象、互斥对象、管道对象、等待计时器对象等都是内核对象。编程时经常要创建、打开和操作它们。内核对象及句柄内核对象由内核拥有,各个进程可以共享内核对象。进程中止执行,它使用的内核对象并不一定会被撤销。每个内核对象都有一个计数器来存储有多少个进程在使用它的信息。进程调用时,计数器增1,调用结束,计数器减1。内核对象计数器为零时,销毁此内核对象。

内核对象及句柄内核对象有安全描述符的保护,安全描述符描述了谁创建了该对象以及谁能够使用该对象。用于创建内核对象的函数几乎都有一个指向SECURITY_ATTRIBUTES

结构的指针作为其参数。

大多数应用程序通过传NULL值,创建具有默认安全性的对象。如果想限制别人对对象的访问,就需要单独创建一个SECURITY_ATTRIBUTES对象并对其初始化。内核对象及句柄句柄:创建内核对象时,函数的返回值,标记该内核对象。句柄表:进程被初始化时,系统给进程分配一个句柄表,用于保存该进程使用的内核对象的信息,而句柄值则是相应内核对象在句柄表中的索引值,因此句柄值是进程相关的。内核对象及句柄内核对象创建当利用creat*函数来创建内核对象时,调用该函数的时候内核就为该对象分配一个内存块,并进行初始化,然后内核再扫描该进程的句柄表,初始化一条记录并放在句柄表中。关闭内核对象无论进程怎样创建内核对象,在不使用该对象的时候都应当通过Bool

CloseHandle(HANDLE

hobj)来向操作统声明结束对该对象的访问。Win32API线程库创建线程程的基本本问题创建线程程的API函数操作线程程的API一个简单单的Windows多线程程程序1创建线程程的基本本问题线程可以以由进程程中的任任意线程程创建,,而进程程的主线线程在进进程加载载时自动动创建。。每个线程程都有自自己的进进入点函函数。主线程的的进入点点函数进入点应用程序类型WinMain需要ANSI字符和字符串的GUI应用程序wWinMain需要Unicode字符和字符串的GUI应用程序Main需要ANSI字符和字符串的CUI应用程序Wmain需要Unicode字符和字符串的CUI应用程序线程函数数的返回回值是该该线程的的退出代代码线程函数数应尽可可能使用用函数参参数和局局部变量量线程函数数----线程的入入口点DWORDWINAPIThreadFunc(PVOIDpvParam){DWORDdwResult=0;……return(dwResult);}2创建线程程的API函数创建线程程:系统统创建一一个线程程内核对对象。线程内核核对象不不是线程程本身,,而是操操作系统统用来管管理线程程的较小小的数据据结构在进程的的地址空空间分配配内存,,供线程程的堆栈栈使用HANDLECreateThread(PSECURITY_ATTRIBUTESpsa,DWORDcbStack,PTHREAD_START_ROUTINEpStartAddr,PVOIDpvParam,DWORDfdwCreate,PDWORDpdwThreadId);2创建线程程的API函数NULL0函数地址址函数参数数NULL控制创建建线程标标志CREATE_SUSPENDED;0线程ID暂停线程程DWORDSuspendThread(HANDLEhThread)返回值是是线程的的前一个个暂停计计数暂停计数数:是线线程内核核对象的的一个内内部值。。使用要小小心,因因为不知知道暂停停线程运运行时它它在进行行什么操操作。可可能造成成死锁3操作线程程的API3操作线程程的API恢复线程程DWORDResumeThread(HANDLEhThread);返回值是是线程的的前一个个暂停计计数该函数用用于将处处于暂停停状态的的线程置置于就绪绪状态,,使其参参加线程程调度。。3操作线程程的API使线程睡睡眠VOIDSleep(DWORDdwMilliseconds);该函数是是线程暂暂停自己己的运行行,直到到睡眠时时间过去去为止当线程调调用这个个函数时时,它自自动放弃弃剩余的的时间片片,迫使使系统进进行线程程调度。。Windows不是实时时的操作作系统。。3操作线程程的API终止线程程线程函数数返回((最好))通过调用用ExitThread函数,线线程将自自行撤销销同一个进进程或另另一个进进程中的的线程调调用TerminateThread函数包含线程程的进程程终止线程返回回函数线程中创创建的C++类对象能能够正常常撤销;;操作系统统将正确确地释放放线程堆堆栈使用用的内存存;系统将线线程的退退出代码码设置为为线程函函数的返返回值;;系统将递递减线程程内核对对象的使使用计数数。线程调用用这个函函数,强强制线程程终止运运行;操作系统统清除该该线程使使用的所所有系统统资源。。C++类对象将将不被撤撤销。VOIDExitThread(DWORDdwExitCode);ExitThread函数能够撤销销任何线线程;线程的内内核对象象的使用用计数也也被递减减;异步运行行的函数数;不撤销线线程的堆堆栈,直直到进程程终止。。BOOLTerminateThread(HANDLEhThread,DWORDdwExitCode);TerminateThread函数在进程终终止运行行时撤销销线程ExitProcess和TerminateProcess函数可以以终止线线程,将将会终止止进程中中的所有有线程;;ExitProcess只能强制制执行本本进程的的退出;;TerminateProcess在一个进进程中强强制结束束其他的的进程;;进程所使使用的资资源被清清除;C++对象撤销函数数没有被调用用。VOIDExitProcess(UINTuExitCode);BOOLTerminateProcess(HANDLEhProcess,UINTuExitCode);在进程终止运运行时撤销线线程4一个简单的Windows多线程程序((例1)include"windows.h"#include<iostream>usingnamespacestd;DWORDWINAPIThreadFunc(PVOIDpvParam){cout<<"Createdthreadsays'helloWorld!'"<<endl;return0;}intmain(){HANDLEThreadHandle=CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);Sleep(100);cout<<"Mainthreadsays'HelloWorld!"<<endl;getchar();return0;}线程间通信操作系统随机机调度线程,,程序员不能能预知线程的的执行顺序下面两种情况况下,线程间间需要通信当有多个线程程访问共享资资源而不希望望共享资源遭遭到破坏;((互斥)当一个线程需需要将某个任任务已经完成成的情况通知知另外一个或或多个线程时时。(同步))Windows线程通信方法法主要有互锁锁函数、临界界段、事件、互斥量量、信号量线程间通信互锁函数临界段事件互斥量信号量1、互锁函数互锁函数是用用来解决原子子访问的,主主要针对变量量的原子访问问;原子访问:当当线程访问资资源时,能够够确保没有其其它线程同时时访问相同的的资源。Longg_x=0;//全局变量DWORDWINAPIThreadFunc1(PVOIDpvParam){g_x++;return0;}DWORDWINAPIThreadFunc2(PVOIDpvParam){g_x++;return0;}MOVEAX,[g_x]INCEAXMOV[g_x],EAX递增以原子方方式运行1、互锁函数((例)1、互锁函数LONGInterlockedExchangeAdd()(PLONGplAddend,LONGlIncrement);Longg_x=0;//全局变量DWORDWINAPIThreadFunc1(PVOIDpvParam){InterlockedExchangeAdd(&g_x,1);return0;}DWORDWINAPIThreadFunc2(PVOIDpvParam){InterlockedExchangeAdd(&g_x,1);return0;}1、互锁函数以原子操作方方式用第二个个参数的值取取代第一个参参数的当前值值。LONGInterlockedExchange()(PLONGplTarget,LONGlValue);LONGInterlockedExchangePointer()(PVOID*ppvTarget,PVOIDpvValue);1、互锁函数比较第一个参参数所指的值值和第三个参参数的值,如如果相等,则则将第一个参参数所指的值值置为第二个个参数,如果果不相等则不不进行任何操操作。LONGInterlockedCompareExchange()(PLONGplDestination,LONGlExchange,LONGlComparand);LONGInterlockedCompareExchangePointer()(PVOID*ppvDestination,PVOIDpvExchange,PVOIDpvComparand);2、临界段互锁函数:以以原子操作方方式修改单个个值临界段:以原原子方式修改改复杂的数据据结构。临界段:关键键代码段,是是指一小段代代码,同一个个时刻,只能能有一个线程程具有访问权权。多个线程访问问同一个临界界区的原则::一次最多只能能一个线程停停留在临界区区内;不能让一个线线程无限地停停留在临界区区内,否则其其它线程将不不能进入该临临界区2、临界段相相关API函数首先定义一个个临界段对象象(通常全局局变量)CRITICAL_SECTIONcs临界段对象初初始化InitializeCriticalSection(&cs)进入临界段EnterCriticalSection(&cs)离开临界段LeaveCriticalSection(&cs)释放临界段对对象DeleteCriticalSection(&cs)临界段例例#include<windows.h>#include<fstream>fstreamfile;DWORDWINAPIThreadFunc1(PVOIDparam){for(inti=1;i<=1000;i++){file<<"ThreadFunc1Output"<<i<<endl;}return0;}DWORDWINAPIThreadFunc2(PVOIDparam){for(inti=1;i<=1000;i++){file<<"ThreadFunc2Output"<<i<<endl;}return0;}intmain(){file.open("data.txt",ios::out);HANDLEThreadHandle1=CreateThread(NULL,0,ThreadFunc1,NULL,0,NULL);HANDLEThreadHandle2=CreateThread(NULL,0,ThreadFunc2,NULL,0,NULL);HANDLEhThread[2]={ThreadHandle1,ThreadHandle2};WaitForMultipleObjects(2,hThread,TRUE,INFINITE);file.close();return0;}加上临界段段#include<windows.h>#include<fstream>fstreamfile;CRITICAL_SECTIONcs;DWORDWINAPIThreadFunc1(PVOIDparam){for(inti=1;i<=1000;i++){EnterCriticalSection(&cs);file<<"ThreadFunc1Output"<<i<<endl;LeaveCriticalSection(&cs);}return0;}DWORDWINAPIThreadFunc2(PVOIDparam){for(inti=1;i<=1000;i++){EnterCriticalSection(&cs);file<<"ThreadFunc2Output"<<i<<endl;LeaveCriticalSection(&cs);}return0;}使用内核对对象的线程程间通信互锁函数和和临界段都都是在用户户态实现线线程通信的的,优点速速度快用户态机制制只能实现现同一进程程内线程通通信。内核对象机机制可以实实现不同进进程内线程程的通信,,缺点速度度慢。包含通知状状态和未通通知状态内内核属性的内核对象象有:进程,线程程,作业,文文件,控制制台输入文件修改通通知,事件件,可等待待定时器信号量,互互斥量等待函数::使线程进进入等待状状态,直到一个对对象变为已已通知状态态。DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds);参数dwMilliseconds有两个特殊殊值:0,则该函数数立即返回回;INFINITE,则线程被被挂起,直直到hHandle所指向的对对象变为已已通知状态态。使用用内内核核对对象象的的线线程程间间通通信信等待待函函数数::可以以保保证证线线程程的的同同步步。DWORDWaitForMultipleObject(DWORDdwCount,CONSTHANDLE*phHandle,BOOLfWaitAll,DWORDdwMilliseconds);使用用内内核核对对象象的的线线程程间间通通信信3、事事件件事件件内内核核对对象象是是最最简简单单的的对对象象。。一个个使使用用计计数数一个个布布尔尔值值,,指指明明该该事事件件是是自自动动重重置置事事件件((false),,还还是是人人工工重重置置事事件件((true);;一个个布布尔尔值值,,指指明明该该事事件件是是已已通通知知状状态态,,还还是是未未通通知知状状态态。。当人人工工重重置置事事件件得得到到通通知知时时,,等等待待该该事事件件的的所所有有线线程程均均变变为为可可调调度度事事件件;;当自自动动重重置置事事件件得得到到通通知知时时,,等等待待该该事事件件的的线创建建事事件件内内核核对对象象,,返返回回句句柄柄。。HANDLECreateEvent(PSECURITY_ATTRIBUTESpsa,//安全全属属性性BOOLfManualReset,//重置置方方式式BOOLfInitialState,//初始始状状态态PCTSTRpszName//对象象名名称称);3、事事件件其它它进进程程中中的的线线程程可可以以获获得得事事件件对对象象的的访访问问权权HANDLEOpenEvent(DWORDfdwAccess,BOOLfInherit,PCTSTRpszName);EVENT_ALL_ACCESS3、事件一旦事件件已经创创建,就就可以直直接控制制它的状状态将事件设设置为已已通知状状态BOOLSetEvent(HANDLEhEvent);将事件设设置为未未通知状状态BOOLResetEvent(HANDLEhEvent);3、事件3、事件事件的主主要用途途是标志志事件的的发生,,并以此此协调线线程的执执行顺序序。例子:用用户在主主线程输输入命令令,控制制新建线线程的运运行。#include<windows.h>#include<iostream>#include<string>usingnamespacestd;CRITICAL_SECTIONcs;DWORDWINAPIThreadFunc(PVOIDparam){EnterCriticalSection(&cs);cout<<"CreateThread:Createthreadisstarted"<<endl;cout<<"CreateThread:Createthreadiswaitingcontinuecommand.."<<endl;LeaveCriticalSection(&cs);HANDLEphEvent=OpenEvent(EVENT_ALL_ACCESS,TRUE,"ContinueCommand");WaitForSingleObject(phEvent,INFINITE);cout<<"CreateThread:Recievedcontinuecommand."<<endl;cout<<"CreateThread:Threadrunsagain."<<endl;Sleep(2000);cout<<"CreateThread:Threadfinished."<<endl;return0;}intmain(){InitializeCriticalSection(&cs);HANDLEhEvent=CreateEvent(NULL,FALSE,FALSE,"ContinueCommand");cout<<"MainThread:Creatingnewthread."<<endl;HANDLEThreadHandle=CreateThread(NULL,0,ThreadFunc,NULL,CREATE_SUSPENDED,NULL);cout<<"MainThread:Newthreadcreated."<<endl;ResumeThread(ThreadHandle);stringinput;while(TRUE){EnterCriticalSection(&cs);cout<<"MainThread:inputcommand,please"<<endl;LeaveCriticalSection(&cs);cout<<">";cin>>input;if(input=="continue"){cout<<"MainThread:Letthreadcontinuerun"<<endl;SetEvent(hEvent);break;}}WaitForSingleObject(ThreadHandle,INFINITE);cout<<"MainThread:Createthreadfinished"<<endl;DeleteCriticalSection(&cs);CloseHandle(hEvent);return0;}4、互斥量量互斥量是是一个种种内核对对象,确确保线程程拥有对对单个资资源的互互斥访问问权。一个使用用数量一个线程程ID一个递归归计数器器互斥量的的行为特特征与临临界段相相同,互互斥量属属于内核核对象,,而临界界段属于于用户方方式对象象。互斥量的的线程ID标识系统统中哪个个线程拥拥有互斥斥量,为为0,没有线线程拥有有递归计数数器指明明线程拥拥有互斥斥量的次次数4、互斥量量经常用于于保护多多个线程程访问的的内存块块;控制对共共享资源源的访问问保证每次次只能有有一个线线程获得得互斥量量4、互斥量量互斥量的的创建,,返回句句柄HANDLECreateMutex(PSECURITY_ATTRIBUTESpsa,//安全属性性的指针针BOOLbInitialOwner,//初始化互互斥对象象的所有有者PCTSTRpszName//指向互互斥对对象名名的指指针);4、互斥斥量另一个个进程程可获获得本本进程程相关关的互互斥量量的句句柄HANDLEOpenMutex(DWORDfdwAccess,//accessBOOLbInheritHandle,//inheritanceoptionPCTSTRpszName//objectname);释放互互斥量量HANDLEReleaseMutex(HANDLEhMutex);等待互互斥量量DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds);互斥量量不同同于其其它内内核对对象,,互斥斥对象象有一一个““线程程所有4、互斥斥量#include<windows.h>#include<fstream>usingnamespacestd;fstreamfile;DWORDWINAPIThreadFunc1(PVOIDparam){HANDLE*phMutex=(HANDLE*)param;for(inti=1;i<=100;i++){WaitForSingleObject(*phMutex,INFINITE);file<<"ThreadFunc1Output"<<i<<endl;ReleaseMutex(*phMutex);}return0;}DWORDWINAPIThreadFunc2(PVOIDparam){HANDLE*phMutex=(HANDLE*)param;for(inti=1;i<=100;i++){WaitForSingleObject(*phMutex,INFINITE);file<<"ThreadFunc2Output"<<i<<endl;ReleaseMutex(*phMutex);}return0;}intmain(){file.open("data.txt",ios::out);HANDLEhMutex=CreateMutex(NULL,FALSE,"DisplayMutex");HANDLEThreadHandle1=CreateThread(NULL,0,ThreadFunc1,&hMutex,0,NULL);HANDLEThreadHandle2=CreateThread(NULL,0,ThreadFunc2,&hMutex,0,NULL);HANDLEhThread[2]={ThreadHandle1,ThreadHandle2};WaitForMultipleObjects(2,hThread,TRUE,INFINITE);CloseHandle(hMutex);file.close();return0;}5、信号量信号量是一一个内核对对象,可用用来管理大大量有限的的系统资源源一个使用计计数32位整数,最最大资源数数量32位整数,当当前资源数数量信号量使用用规则:当前资源数数量大于0,则等待信信号量的线线程获得资资源继续运运行,当前前资源数量量减1当前资源数数量等于0,则等待信信号量的线线程继续等等待,直到到有线程释释放信号量量,使当前前资源数量量大于0创建信号量量5、信号量HANDLECreateSemaphore(PSECURITY_ATTRIBUTESpsa,LONGlInitialCount,//initialcountLONGlMaximumCount,//maximumcountPCTSTRpszName//objectname);另一进程可可获得与本本进程相关关的信号量量的句柄5、信号量HANDLEOpenSemaphore(DWORDfdwAccess,BOOLbInheritHandle,//inheritanceoptionPCTSTRpszName//objectname);释放信号量量例,两个线线程分别有有一个初值值为0的Int型局部变量量,两个线线程的行为为是在一个个循环中,,使整型变变量递增,,一个约束束条件,在在递增过程程中,这两两个值的差差不超过5ReleaseSemaphore(HANDLEhSem,LONGlReleaseCount,PLONGplPreviousCount);5、信号量HANDLEhsem1=CreateSemaphore(NULL,5,10,"sem1");HANDLEhsem2=CreateSemaphore(NULL,5,10,"sem2");inti1=0;inti2=0;DWORDWINAPIThreadFunc1(PVOIDparam){for(inti=1;i<=100;i++){WaitForSingleObject(hsem1,INFINITE);ReleaseSemaphore(hsem2,1,NULL);i1++;file<<"i1="<<i1<<"i2="<<i2<<endl;}return0;}DWORDWINAPIThreadFunc2(PVOIDparam){for(inti=1;i<=100;i++){WaitForSingleObject(hsem2,INFINITE);ReleaseSemaphore(hsem1,1,NULL);i2++;file<<"i1="<<i1<<"i2="<<i2<<endl;}return0;}线程的优先先级决定它它何时运行行和接收多多少CPU时间。优先级共32级,是从0到31的数值,称称为基本优优先级别。。0-15级是普通优优先级线程的优先先级可以动动态变化高优先级线线程优先运运行,只有有高优先级级线程不运运行时,才才调度低优优先级线程程运行。优先级相同同的线程按按照时间片片轮流运行行。进程与线程程的优先级级进程与线程程的优先级级16-31级是实时优优先级相同优先级级线程的运运行不按照照时间片轮轮转,而是是先运行的的线程就先先控制CPU,如果它不

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论