




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
四种进程或线程同步互斥的控制方法1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。2、互斥量:为协调共同对一个共享资源的单独访问而设计的。3、信号量:为控制一个具有有限数量用户资源而设计。4、事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。一临界区临界区的使用在线程同步中应该算是比较简单,说它简单还是说它同后面讲到的其它方法相比更容易理解。举个简单的例子:比如说有一个全局变量(公共资源)两个线程都会对它进行写操作和读操作,如果我们在这里不加以控制,会产生意想不到的结果。假设线程A正在把全局变量加1然后打印在屏幕上,但是这时切换到线程B,线程B又把全局变量加1然后又切换到线程A,这时候线程A打印的结果就不是程序想要的结果,也就产生了错误。解决的办法就是设置一个区域,让线程A在操纵全局变量的时候进行加锁,线程B如果想操纵这个全局变量就要等待线程A释放这个锁,这个也就是临界区的概念。二互斥体windowsapi中提供了一个互斥体,功能上要比临界区强大。也许你要问,这个东东和临界区有什么区别,为什么强大?它们有以下几点不一致:1.criticalsection是局部对象,而mutex是核心对象。因此像waitforsingleobject是不可以等待临界区的。2.criticalsection是快速高效的,而mutex同其相比要慢很多3.criticalsection使用范围是单一进程中的各个线程,而mutex由于可以有一个名字,因此它是可以应用于不同的进程,当然也可以应用于同一个进程中的不同线程。4.criticalsection无法检测到是否被某一个线程释放,而mutex在某一个线程结束之后会产生一个abandoned的信息。同时mutex只能被拥有它的线程释放。下面举两个应用mutex的例子,一个是程序只能运行一个实例,也就是说同一个程序如果已经运行了,就不能再运行了;另一个是关于非常经典的哲学家吃饭问题的例子。三事件事件对象的特点是它可以应用在重叠I/O(overlappedI/0)上,比如说socket编程中有两种模型,一种是重叠I/0,一种是完成端口都是可以使用事件同步。它也是核心对象,因此可以被waitforsingleobje这些函数等待;事件可以有名字,因此可以被其他进程开启。四信号量semaphore的概念理解起来可能要比mutex还难,我先简单说一下创建信号量的函数,因为我在开始使用的时候没有很快弄清楚,可能现在还有理解不对的地方,如果有错误还是请大侠多多指教。CreateSemaphore(LPSECURITY_ATTRIBUTESlpSemaphoreAttributes,//SDLONGlInitialCount,//initialcountLONGlMaximumCount,//maximumcountLPCTSTRlpName//objectname)第一个参数是安全性,可以使用默认的安全性选项NULL;第二个和第三个参数是两个long型的数值,它们表示什么含义呢?lMaxinumCount表示信号量的最大值,必须要大于零。比如是5就表示可以有5个进程或者线程使用,如果第六个进程或者线程想使用的话就必须进入等待队列等待有进程或者线程释放资源。lInitalCount表示信号量的初始值,应该大于或者等于零小于等于lMaximumCount。如果lInitialCount=0&&lMaximumCount==5,那么就表示当前资源已经全部被使用,如果再有进程或者线程想使用的话,信号量就会变成-1,该进程或者线程进入等待队列,直到有进程或者线程执行ReleaseMutex;如果lInitialCount=5&&lMaximumCount==5,那么就表示现在信号量可以被进程或者线程使用5次,再之后就要进行等待;如果InitialCount=2&&MaximumCount==5这样的用法不太常见,表示还可以调用两次CreateSemaphore或者OpenSemaphore,再调用的话就要进入等待状态。最后一个参数表示这个信号量的名字,这样就可以跨进程的时候通过这个名字OpenSemaphore。总结:1.互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,所以如果只为了在进程内部是用的话使用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。2.互斥量(Mutex),信号灯(Semaphore),事件(Event)都可以被跨越进程使用来进行同步数据操作,而其他的对象与数据同步操作无关,但对于进程和线程来讲,如果进程和线程在运行状态则为无信号状态,在退出后为有信号状态。所以可以使用WaitForSingleObject来等待进程和线程退出。3.通过互斥量可以指定资源被独占的方式使用,但如果有下面一种情况通过互斥量就无法处理,比如现在一位用户购买了一份三个并发访问许可的数据库系统,可以根据用户购买的访问许可数量来决定有多少个线程/进程能同时进行数据库操作,这时候如果利用互斥量就没有办法完成这个要求,信号灯对象可以说是一种资源计数器。六。CreateMutex()与CreateEvent()区别使用CreateMutex()来产生一个Mutex物件,而传入的Mutex名称字串用以区别不同的Mutex,也就是说,不管是哪个Process/Thread,只要传入的名称叁数是相同的一个字串,那CreateMutex()传回值(hMutex,handleofMutex)会指向相同的一个Mutex物件。这和Event物件相同。然而Mutex和Event有很大的不同,Mutex有Owner的概念,如果Mutex为ThreadA所拥有,那麽ThreadA执行WaitForSingleObject()时,并不会停下来,而会立即传回WAIT_OBJECT_0,而其他的Thread执行WaitForSingleObject()则会停下来,直到Mutex的所有权被Release出来或TimeOut。如果一个Thread已取得Mutex的所有权,而它呼叫WaitForSingleObject()n次,则也要使用ReleaseMutexn次才能够将Mutex的拥有权放弃,这和Event也不同,而且,非Mutex拥有者呼叫ReleaseMutex也不会有任何作用。而每次以WaitForSingleObject呼叫一次,Mutex会有一个计数器会加一,ReleaseMutex成功会减一,直到Mutex的计数器为0之後,系统才会将之去除。临界区(CriticalSection)
保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。
临界区包含两个操作原语:
EnterCriticalSection()进入临界区
LeaveCriticalSection()离开临界区
EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。
MFC提供了很多功能完备的类,我用MFC实现了临界区。MFC为临界区提供有一个CCriticalSection类,使用该类进行线程同步处理是非常简单的。只需在线程函数中用CCriticalSection类成员函数Lock()和UnLock()标定出被保护代码片段即可。Lock()后代码用到的资源自动被视为临界区内的资源被保护。UnLock后别的线程才能访问这些资源。互斥量(Mutex)
互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。互斥量比临界区复杂。因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。
互斥量包含的几个操作原语:
CreateMutex()创建一个互斥量
OpenMutex()打开一个互斥量
ReleaseMutex()释放互斥量
WaitForMultipleObjects()等待互斥量对象
同样MFC为互斥量提供有一个CMutex类。使用CMutex类实现互斥量操作非常简单,但是要特别注意对CMutex的构造函数的调用
CMutex(BOOLbInitiallyOwn=FALSE,LPCTSTRlpszName=NULL,LPSECURITY_ATTRIBUTESlpsaAttribute=NULL)
不用的参数不能乱填,乱填会出现一些意想不到的运行结果。信号量(Semaphores)
信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。它指出了同时访问共享资源的线程最大数目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore()创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就会减1,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目,不能在允许其他线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。
PV操作及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。信号量S是一个整数,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用共享资源的进程数。
P操作申请资源:
(1)S减1;
(2)若S减1后仍大于等于零,则进程继续执行;
(3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转入进程调度。
V操作释放资源:
(1)S加1;
(2)若相加结果大于零,则进程继续执行;
(3)若相加结果小于等于零,则从该信号的等待队列中唤醒一个等待进程,然后再返回原进程继续执行或转入进程调度。
信号量包含的几个操作原语:
CreateSemaphore()创建一个信号量
OpenSemaphore()打开一个信号量
ReleaseSemaphore()释放信号量
WaitForSingleObject()等待信号量事件(Event)
事件对象也可以通过通知操作的方式来保持线程的同步。并且可以实现不同进程中的线程同步操作。
信号量包含的几个操作原语:
CreateEvent()创建一个信号量
OpenEvent()打开一个事件
SetEvent()回置事件
WaitForSingleObject()等待一个事件
WaitForMultipleObjects()等待多个事件
WaitForMultipleObjects函数原型:
WaitForMultipleObjects(
INDWORDnCount,//等待句柄数
INCONSTHANDLE*lpHandles,//指向句柄数组
INBOOLbWaitAll,//是否完全等待标志
INDWORDdwMilliseconds//等待时间
)
参数nCount指定了要等待的内核对象的数目,存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式进行了指定,为TRUE时当所有对象都被通知时函数才会返回,为FALSE则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与在WaitForSingleObject()中的作用是完全一致的。如果等待超时,函数将返回WAIT_TIMEOUT。总结:
1.互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,所以如果只为了在进程内部是用的话使用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。
2.互斥量(Mutex),信号灯(Semaphore),事件(Event)都可以被跨越进程使用来进行同步数据操作,而其他的对象与数据同步操作无关,但对于进程和线程来讲,如果进程和线程在运行状态则为无信号状态,在退出后为有信号状态。所以可以使用WaitForSingleObject来等待进程和线程退出。
3.通过互斥量可以指定资源被独占的方式使用,但如果有下面一种情况通过互斥量就无法处理,比如现在一位用户购买了一份三个并发访问许可的数据库系统,可以根据用户购买的访问许可数量来决定有多少个线程/进程能同时进行数据库操作,这时候如果利用互斥量就没有办法完成这个要求,信号灯对象可以说是一种资源计数器。首选使用临界区对象,主要原因是使用简单。EnterCriticalSection()函数等候指定的危险区段对象的所有权。当调用的线程被允许所有权时,函数返回。EnterCriticalSection(),一个单独进程的线程可以使用一个危险区段对象作为相互-排除同步。进程负责分配被一个危险区段对象使用的内存,它藉由声明一个CRITICAL_SECTION类型的变量实现。在使用一个危险区段之前,进程的一些线程必须调用InitializeCriticalSection函数设定对象的初值.为了要使互斥的访问被共享的资源,每个线程调用EnterCriticalSection或者TryEnterCriticalSection功能,在执行访问被保护资源的任何代码段之前,请求危险区段的所有权。#include<windows.h>#include<iostream>usingnamespacestd;DWORDWINAPIFun1Proc(LPVOIDlpParameter);DWORDWINAPIFun2Proc(LPVOIDlpParameter);inttickets=100;CRITICAL_SECTIONg_csA;CRITICAL_SECTIONg_csB;voidmain(){HANDLEhThread1;HANDLEhThread2;hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);InitializeCriticalSection(&g_csA);InitializeCriticalSection(&g_csB);Sleep(40000);DeleteCriticalSection(&g_csA);DeleteCriticalSection(&g_csB);}DWORDWINAPIFun1Proc(LPVOIDlpParameter){while(TRUE){EnterCriticalSection(&g_csA);Sleep(1);//EnterCriticalSection(&g_csB);//临界区的同步和互锁if(tickets>0){Sleep(1);cout<<"Thread1sellticket:"<<tickets--<<endl;//LeaveCriticalSection(&g_csB);LeaveCriticalSection(&g_csA);}else{//LeaveCriticalSection(&g_csB);LeaveCriticalSection(&g_csA);break;}}return0;}DWORDWINAPIFun2Proc(LPVOIDlpParameter){while(TRUE){EnterCriticalSection(&g_csB);Sleep(1);EnterCriticalSection(&g_csA);if(tickets>0){Sleep(1);cout<<"Thread2sellticket:"<<tickets--<<endl;LeaveCriticalSection(&g_csA);LeaveCriticalSection(&g_csB);}else{LeaveCriticalSection(&g_csA);LeaveCriticalSection(&g_csB);break;}}return0;}二、使用互斥对象DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds);如果时间是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUTWaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。#include<windows.h>#include<iostream>usingnamespacestd;DWORDWINAPIFun1Proc(LPVOIDlpParameter);DWORDWINAPIFun2Proc(LPVOIDlpParameter);intindex=0;inttickets=100;HANDLEhMutex;voidmain(){HANDLEhThread1;HANDLEhThread2;hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);//创建线程hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);//保证应用程序只有一个实例运行,创建一个命名的互斥对象.hMutex=CreateMutex(NULL,TRUE,LPCTSTR("tickets"));//创建时主线程拥有该互斥对象,互斥对象的线程ID为主线程的ID,同时将该互斥对象内部计数器置为1if(hMutex){if(ERROR_ALREADY_EXISTS==GetLastError()){cout<<"onlyoneinstancecanrun!"<<endl;//Sleep(40000);return;}}WaitForSingleObject(hMutex,INFINITE);//使用该函数请求互斥对象时,虽说该对象处于无信号状态,但因为请求的线程ID和该互斥对象所有者的线程ID是相同的.所以仍然可以请求到这个互斥对象,于是该互斥对象内部计数器加1,内部计数器的值为2.意思是有两个等待动作ReleaseMutex(hMutex);//释放一次互斥对象,该互斥对象内部计数器的值递减1,操作系统不会将这个互斥对象变为已通知状态.ReleaseMutex(hMutex);//释放一次互斥对象,该互斥对象内部计数器的值为0,同时将该对象设置为已通知状态.//对于互斥对象来说,谁拥有谁释放Sleep(40000);}DWORDWINAPIFun1Proc(LPVOIDlpParameter){while(TRUE){WaitForSingleObject(hMutex,INFINITE);//等待互斥对象有信号if(tickets>0){Sleep(1);cout<<"thread1sellticket:"<<tickets--<<endl;}elsebreak;ReleaseMutex(hMutex);//设置该互斥对象的线程ID为0,并且将该对象设置为有信号状态}return0;}DWORDWINAPIFun2Proc(LPVOIDlpParameter){while(TRUE){WaitForSingleObject(hMutex,INFINITE);if(tickets>0){Sleep(1);cout<<"thread2sellticket:"<<tickets--<<endl;}elsebreak;ReleaseMutex(hMutex);}return0;}三、使用事件对象HANDLECreateEvent(LPSECURITY_ATTRIBUTESlpEventAttributes,//SDBOOLbManualReset,//resettypeBOOLbInitialState,//initialstateLPCTSTRlpName//objectname);该函数创建一个Event同步对象,并返回该对象的HandlelpEventAttributes一般为NULLbManualReset创建的Event是自动复位还是人工复位 ,如果true,人工复位,一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复为无信号.如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,该Event就会自动复位,变成无信号.bInitialState初始状态,true,有信号,false无信号lpNameEvent对象名一个Event被创建以后,可以用OpenEvent()API来获得它的Handle,用CloseHandle()来关闭它,用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent()来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待其变为有信号.PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于人工复位的Event对象,它释放所有等待的thread.#include<windows.h>#include<iostream>usingnamespacestd;DWORDWINA
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年度电子产品促销活动合作合同
- 2025版皮革行业原材料供应链金融服务合同样本
- 2025版彩钢板施工竣工验收合同
- 2025版时尚服饰店铺联合品牌转让与市场拓展协议
- 2025年度羽毛球比赛场地租赁及赛事支持合同
- 二零二五年度机房设备搬迁与维护保养合作协议
- 2026届重庆市全善中学巴南中学中考英语最后一模试卷含答案
- 《库欣病诊治专家共识(2025)》解读 2
- 国际贸易交易磋商的环节(2025版)
- 规范的车辆使用协议书参考正规2025年
- 水土保持方案投标文件技术部分
- 三基三严培训课件
- 《法律法规常识讲解》课件
- 36种流行病学调查表
- 墓碑购销合同范例
- 小红书食用农产品承诺书示例
- 旧建筑物拆除的BIM流程
- 初中英语单词1600词(完整版)
- 《建筑工程设计文件编制深度规定》(2022年版)
- 屠宰场合作协议书模板
- 安装纱窗工程合同协议书
评论
0/150
提交评论