您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > Windows线程同步和互斥.
Windows线程同步和互斥Windows线程同步机制事件(Event)临界区(CriticalSection)互斥量(Mutex)信号量(Semaphore)同步机制说明互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。如果只为了在进程内部用的话使用临界区会带来速度上的优势并能够减少资源占用量。互斥量是跨进程的,一旦被创建,就可以通过名字打开它。创建互斥量需要的资源更多。同步机制说明(续)互斥量,信号量和事件都可以跨进程来实现同步数据操作。互斥量:资源独占使用信号量:资源计数器事件事件对象可以通过通知操作的方式来保持线程的同步。并且可以实现不同进程中的线程同步操作。事件是WIN32中最灵活的线程间同步机制。事件存在两种状态:激发状态(SignaledorTrue)未激发状态(UnsignaledorFalse)事件事件可分为两类:手动设置:这种对象只可能用程序手动设置,在需要该事件或者事件发生时,采用SetEvent及ResetEvent来进行设置。自动恢复:一旦事件发生并被处理后,自动恢复到没有事件状态,不需要再次设置。事件-函数原型函数原型:HANDLECreateEvent(LPSECURITY_ATTRIBUTESlpEventAttributes,//SECURITY_ATTRIBUTES结构指针,可为NULLBOOLbManualReset,//手动/自动//TRUE:在WaitForSingleObject后必须手动调用ResetEvent清除信号//FALSE:在WaitForSingleObject后,系统自动清除事件信号BOOLbInitialState,//初始状态LPCTSTRlpName//事件的名称);事件-函数原型(续)使用“事件”机制应注意以下事项:如果跨进程访问事件,必须对事件命名,在对事件命名的时候,要注意不要与系统命名空间中的其它全局命名对象冲突;事件是否要自动恢复;事件的初始状态设置。由于event对象属于内核对象,故进程B可以调用OpenEvent函数通过对象的名字获得进程A中event对象的句柄,然后将这个句柄用于ResetEvent、SetEvent和WaitForMultipleObjects等函数中。此法可以实现一个进程的线程控制另一进程中线程的运行,例如:HANDLEhEvent=OpenEvent(EVENT_ALL_ACCESS,true,MyEvent);ResetEvent(hEvent);事件-例子三个线程:主线程读线程写线程读线程必须在写线程操作结束后才能进行读;主线程必须等读和写线程结束后才能结束代码includestdafx.h#includewindows.h#includeprocess.h#includeiostream.h#includefstream.hHANDLEevRead,evFinish;voidReadThread(LPVOIDparam){WaitForSingleObject(evRead,INFINITE);coutReadingendl;SetEvent(evFinish);}voidWriteThread(LPVOIDparam){coutWritingendl;SetEvent(evRead);}代码(续)intmain(intargc,char*argv[]){evRead=CreateEvent(NULL,FALSE,FALSE,NULL);evFinish=CreateEvent(NULL,FALSE,FALSE,NULL);_beginthread(ReadThread,0,NULL);_beginthread(WriteThread,0,NULL);WaitForSingleObject(evFinish,INFINITE);coutEnd.endl;return0;}临界区临界区是保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。临界区(续)临界区包含两个操作原语:EnterCriticalSection()进入临界区LeaveCriticalSection()离开临界区EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。否则,临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。临界区—Win32API创建临界区为了创建临界区,首先必须在进程中分配一个全局CRITICAL_SECTION数据结构:CRITICAL_SECTIONgCriticalSection;使用临界区使用临界区之前,必须调用InitializeCriticalSection函数初始化:VOIDInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);进入临界区调用EnterCriticalSection函数进入临界区:VOIDEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);离开临界区调用LeaveCriticalSection函数退出了临界区:VOIDLeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);删除临界区调用DeleteCriticalSection函数删除临界区:VOIDDeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);临界区-一般用法……EnterCriticalSection(&gCriticalSection);//dosomethingLeaveCriticalSection(&gCriticalSection);……临界区-注意事项关于临界区的使用,有下列注意点:每个共享资源使用一个CRITICAL_SECTION变量;不要长时间运行关键代码段,当一个关键代码段长时间运行时,其他线程就会进入等待状态,这会降低应用程序的运行性能;如果需要同时访问多个资源,则可能连续调用EnterCriticalSection;CriticalSection不是OS核心对象,如果进入临界区的线程挂了,将无法释放临界资源。这个缺点在Mutex中得到了弥补。临界区-例子一个银行系统中两个线程执行取款操作,一个使用ATM机,另一个使用存折在柜台取款。如果不加于控制,会使得账户余额为负数。代码#includestdafx.h#includewindows.h#includeprocess.h#includeiostream.h#includefstream.hinttotal=1000;HANDLEevFin[2];CRITICAL_SECTIONcs;voidWithDrawThread1(LPVOIDparam){EnterCriticalSection(&cs);if((total-900)=0){total-=900;coutyouwithdraw$900.endl;}else{coutNoenoughmoney!endl;}LeaveCriticalSection(&cs);SetEvent(evFin[0]);}代码(续)voidWithDrawThread2(LPVOIDparam){EnterCriticalSection(&cs);if((total-700)=0){total-=700;coutyouwithdraw$700.endl;}else{coutNoenoughmoney!endl;}LeaveCriticalSection(&cs);SetEvent(evFin[1]);}代码(续)intmain(intargc,char*argv[]){evFin[0]=CreateEvent(NULL,FALSE,FALSE,NULL);evFin[1]=CreateEvent(NULL,FALSE,FALSE,NULL);InitializeCriticalSection(&cs);_beginthread(WithDrawThread1,0,NULL);_beginthread(WithDrawThread2,0,NULL);WaitForMultipleObjects(2,evFin,TRUE,INFINITE);DeleteCriticalSection(&cs);couttotalendl;return0;}互斥量互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限。由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。互斥量比临界区复杂。因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。互斥量用CreateMutex函数创建互斥量:HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,//安全属性结构指针,可为NULLBOOLbInitialOwner,//是否占有该互斥量,TRUE:占有,FALSE:不占有LPCTSTRlpName//信号量的名称);其它API打开一个互斥量:OpenMutex函数:HANDLEOpenMutex(DWORDfdwAccess,//值为SYNCHRONIZE或MUTEX_ALL_ACCESSBOOLfInherit,LPTSTRlpszName);释放一个互斥量:ReleaseMutex函数:BOOLReleaseMutex(HANDLEhMutex);该函数将互斥量从无信号状态变到有信号状态。互斥和临界区的比较互斥量-例子代码#includestdafx.h#includewindows.h#includeiostream.h#defineTHREAD_INSTANCE_NUMBER3LONGg_RessourceInUse=FALSE;LONGg_iCounter=0;voidThreadProc(void*pData){intThreadNumTemp=(*(int*)pData);HANDLEhMutex;coutThreadProc:ThreadNumTempinRunning!endl;if((hMutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,Mutex.Test))==NULL)coutOpenmutexerror!endl;WaitForSingleObject(hMutex,INFINITE);coutThreadProc:ThreadNumTempgetsthemutex.endl;ReleaseMutex(hMutex);CloseHandle(hMutex);coutThreadProc:ThreadNumTempend.endl;}互斥量-例子代码(续)intmai
本文标题:Windows线程同步和互斥.
链接地址:https://www.777doc.com/doc-2867670 .html