您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 能源与动力工程 > 化工大学Windows多线程编程
第二章Windows多线程编程内容1.Windows操作系统的一些基本知识2.Win32API线程库3.线程间通信1、Windows操作系统的一些基本知识1.API2.内核对象及句柄API(ApplicationProgrammingInterface)API操作系统留给应用程序的一个调用接口,应用程序通过调用操作系统的API而使操作系统去执行应用程序的命令(动作)。WindowsAPI是一套用来控制Windows的各个部件的外观和行为的预先定义的Windows函数。Win32API即为Microsoft32位平台的应用程序编程接口。Win32平台上运行的应用程序都可以调用这些函数。32与64位API函数声明上没有明显区别,但64位编程是需要下载相应的平台SDKAPI(ApplicationProgrammingInterface)直接用win32API编写的应用程序,程序的执行代码小,运行效率高MFC用类库的方式将win32API进行封装,以类的方式提供给开发者Framework类库提供了所有应用程序模型都要使用的一个面向对象的API集合内核对象及句柄当应用程序要与系统设备进行交互的时候,将使用到内核对象。出于安全的考虑,进程是不能直接访问内核对象的,操作系统提供了对应的函数来对它们进行访问。内核对象是由操作系统内核分配,只能由内核访问的数据结构,用来管理各种系统资源。内核对象包括:存取符号对象、事件对象、文件对象、作业对象、互斥对象、管道对象、等待计时器对象等都是内核对象。编程时经常要创建、打开和操作它们。内核对象及句柄内核对象由内核拥有,各个进程可以共享内核对象。进程中止执行,它使用的内核对象并不一定会被撤销。每个内核对象都有一个计数器来存储有多少个进程在使用它的信息。进程调用时,计数器增1,调用结束,计数器减1。内核对象计数器为零时,销毁此内核对象。内核对象及句柄内核对象有安全描述符的保护,安全描述符描述了谁创建了该对象以及谁能够使用该对象。用于创建内核对象的函数几乎都有一个指向SECURITY_ATTRIBUTES结构的指针作为其参数。大多数应用程序通过传NULL值,创建具有默认安全性的对象。如果想限制别人对对象的访问,就需要单独创建一个SECURITY_ATTRIBUTES对象并对其初始化。内核对象及句柄句柄:创建内核对象时,函数的返回值,标记该内核对象。句柄表:进程被初始化时,系统给进程分配一个句柄表,用于保存该进程使用的内核对象的信息,而句柄值则是相应内核对象在句柄表中的索引值,因此句柄值是进程相关的。内核对象及句柄内核对象创建当利用creat*函数来创建内核对象时,调用该函数的时候内核就为该对象分配一个内存块,并进行初始化,然后内核再扫描该进程的句柄表,初始化一条记录并放在句柄表中。关闭内核对象无论进程怎样创建内核对象,在不使用该对象的时候都应当通过BoolCloseHandle(HANDLEhobj)来向操作统声明结束对该对象的访问。Win32API线程库1.创建线程的基本问题2.创建线程的API函数3.操作线程的API4.一个简单的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)includewindows.h#includeiostreamusingnamespacestd;DWORDWINAPIThreadFunc(PVOIDpvParam){coutCreatedthreadsays'helloWorld!'endl;return0;}intmain(){HANDLEThreadHandle=CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);Sleep(100);coutMainthreadsays'HelloWorld!endl;getchar();return0;}线程间通信操作系统随机调度线程,程序员不能预知线程的执行顺序下面两种情况下,线程间需要通信当有多个线程访问共享资源而不希望共享资源遭到破坏;(互斥)当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程时。(同步)Windows线程通信方法主要有互锁函数、临界段、事件、互斥量、信号量线程间通信1.互锁函数2.临界段3.事件4.互斥量5.信号量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)临界段例#includewindows.h#includefstreamfstreamfile;DWORDWINAPIThreadFunc1(PVOIDparam){for(inti=1;i=1000;i++){fileThreadFunc1Outputiendl;}return0;}DWORDWINAPIThreadFunc2(PVOIDparam){for(inti=1;i=1000;i++){fileThreadFunc2Outputiendl;}return0;}intmain(){file.open(data.txt,ios::out);HANDLEThreadHandle1=CreateThread(NULL,0,ThreadFunc1,NULL,0,NULL);HANDLEThreadHandle2=CreateThread(NULL,0,Thre
本文标题:化工大学Windows多线程编程
链接地址:https://www.777doc.com/doc-262758 .html