zoukankan      html  css  js  c++  java
  • 事件EVENT与waitforsingleobject的使用以及Mutex与Event的区别

    Mutex与Event控制互斥事件的使用详解
    
    最近写一程序,误用了Mutex的功能,错把Mutex当Event用了。
    
    【Mutex】
    
    使用Mutex的主要函数:CreateMutex、ReleaseMutex、OpenMutex、WaitForSingleObject、WaitForMultipleObjects。
    
    CreateMutex:其中第二个参数是表示当前线程拥有权。
    
    TRUE:创建线程获得初始所有权的互斥对象(即信号已被当前线程获得,没有释放前其它线程不能获得。如果当前线程调用了WaitForSingleObject   函 数, 则释放次数等于调用次数加1)。     
    
     FALSE:创建线程没有获得互斥对象的所有权。也就是自由争取,看谁先Wait到。 不管怎么样,MUtex的释放规则是:谁拥有谁释放,还有在线程结束时, 线程所获得的Mutex自动释放;当然还可以使用命名Mutex做唯一性验证,这个在整个windows生存期下有效。
    
    【Event】
    
    与Mutex不一样,Event是任何时候都是可以操作的,而且没有同调用多次WaitForSingleObject和同时释放多次一说。
    
    它的主要操作函数有:  CreateEvent、SetEvent、WaitForSingleObject。
    
    CreateEvent参数说明。
    
    第二个参数表示调用WaitForSingleObject后手动(TRUE)/自动(FALSE)为无信号状态。
    
    第三个参数表示初始状态为有(TRUE)/无(FALSE)信号。  
    
    Event的获得是通过一个队列去排队获得的,SetEvent没有限制使用,在任何可以调用的地方都可以调用。
    
    Mutex,的互斥是以线程为基本单位,而Event是以代码段为基本单位。所以在两者的使用上有着不同的功能用途。
    
    https://www.cnblogs.com/upendi/archive/2013/02/25/2932154.html
    
    事件EVENT与waitforsingleobject的使用 
    
    
    事件event与waitforsingleobject的配合使用,能够解决很多同步问题,也可以在数据达到某个状态时启动另一个线程的执行,如报警。
    
    event的几个函数:
    
    1、CreateEvent和OpenEvent
    
    
     HANDLE WINAPI CreateEvent(
       __in          LPSECURITY_ATTRIBUTES lpEventAttributes,    //表示安全控制,一般直接传入NULL,表示不能被子进程继承
       __in          BOOL bManualReset,  //参数确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。
       __in          BOOL bInitialState,  //Event的初始状态, TRUE为触发,FALSE未触发
      __in          LPCTSTR lpName   //Event object的名字,NULL表示没名字(without a name)
     );
    
    
    要是CreateEvent创建的事件没名字  这个函数就没啥用了,不多做介绍,可查看msn。
    1 HANDLE WINAPI OpenEvent(                   //获得已经存在的Event的事件句柄
    2   __in          DWORD dwDesiredAccess,
    3   __in          BOOL bInheritHandle,
    4   __in          LPCTSTR lpName       //要打开的事件名字
    5 );
    
    
    2、SetEvent,触发事件
    
     BOOL SetEvent(HANDLE hEvent);
    
    3、ResetEvent,使事件状态设为未触发,如在创建事件时第二个参数为TRUE手动设置,则需要该函数去恢复事件为未触发状态。
    
    BOOL SetEvent(HANDLE hEvent);
    
    4、PulseEvent, 如在创建事件时第二个参数为TRUE手动设置,其功能相当于SetEvent()后立即调用ResetEvent()
     BOOL PulseEvent(HANDLE hEvent)
    
    也就是说在自动重置模式下PulseEvent和SetEvent的作用没有什么区别,但在手动模式下PulseEvent就有明显的不同, 可以比较容易的控制程序是单步走,还是连续走。如果让循环按要求执行一次就用PulseEvent,如果想让循环连续不停的运转就用SetEvent ,在要求停止的地方发个ResetEvent就OK了。
    
    5、CloseHandle(),关闭该句柄。
    
    **********
    
    WaitForSingleObject函数。使线程处于等待状态,如等待某一事件的触发。
    
    DWORD WINAPI WaitForSingleObject(
    
     HANDLE hHandle,                   //等待的触发句柄  ,  如前面说的Event的句柄
    
     DWORD dwMilliseconds             //等待多长时间,单位ms   如5000 则为5s   若为INFINITE表示无限等待
    );
    

     http://www.cnblogs.com/LouMengzhao/p/6076368.html

    http://blog.sina.com.cn/s/blog_6163bdeb0100qlw1.html

    事件和其他量一样,也是一个内核对象。
    
    使用事件可以进行同步,主要是可以规定先后顺序。
    
    事件分为手动置位事件和自动置位事件,两个的关系是什么呢?
    
    手动置位事件就是你一旦触发之后,所有的状态都被释放。
    
    自动置位事件你触发之后,只有一个状态被释放,这个时候就有不确定性了。
    
     
    
     
    
    如何使用事件?有这么几个函数。
    
    第一个 CreateEvent
    
    函数功能:创建事件
    
    函数原型:
    
    HANDLECreateEvent(
    
     LPSECURITY_ATTRIBUTESlpEventAttributes,
    
     BOOLbManualReset,
    
     BOOLbInitialState,
    
     LPCTSTRlpName
    
    );
    
    函数说明:
    
    第一个参数表示安全控制,一般直接传入NULL。
    
    第二个参数确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。如果为自动置位,
    则对该事件调用WaitForSingleObject()后会自动调用ResetEvent()使事件变成未触发状态。打个小小比方,
    手动置位事件相当于教室门,教室门一旦打开(被触发),所以有人都可以进入直到老师去关上教室门(事件变成未触发)。
    自动置位事件就相当于医院里拍X光的房间门,门打开后只能进入一个人,这个人进去后会将门关上,其它人不能进入除非门重新被打开(事件重新被触发)。 第三个参数表示事件的初始状态,传入TRUR表示已触发。 第四个参数表示事件的名称,传入NULL表示匿名事件。 第二个 OpenEvent 函数功能:根据名称获得一个事件句柄。 函数原型: HANDLEOpenEvent( DWORDdwDesiredAccess, BOOLbInheritHandle, LPCTSTRlpName //名称 ); 函数说明: 第一个参数表示访问权限,对事件一般传入EVENT_ALL_ACCESS。详细解释可以查看MSDN文档。 第二个参数表示事件句柄继承性,一般传入TRUE即可。 第三个参数表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个事件。 第三个SetEvent 函数功能:触发事件 函数原型:BOOLSetEvent(HANDLEhEvent); 函数说明:每次触发后,必有一个或多个处于等待状态下的线程变成可调度状态。 第四个ResetEvent 函数功能:将事件设为末触发 函数原型:BOOLResetEvent(HANDLEhEvent); 最后一个事件的清理与销毁 由于事件是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。 关于之前的那个问题,如何来设置同步呢? 首先是初始化: ​ •//事件与关键段 •HANDLE g_hThreadEvent; •CRITICAL_SECTION g_csThreadCode; • • //初始化事件和关键段 自动置位,初始无触发的匿名事件 • g_hThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); • InitializeCriticalSection(&g_csThreadCode); • //销毁事件和关键段 • CloseHandle(g_hThreadEvent); • DeleteCriticalSection(&g_csThreadCode); •​ • •关键代码段修改: •主循环当中: • while (i < THREAD_NUM) • { • handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL); • WaitForSingleObject(g_hThreadEvent, INFINITE); //等待事件被触发 i++; • } •线程函数当中: •​ •int nThreadNum = *(int *)pPM; • SetEvent(g_hThreadEvent); //触发事件 于是就可完成同步工作。 匿名和有名的差别: 匿名的时候具有亲缘关系的才能看到,而有名管道则可以在其他进程当中看到,这个是大部分的差别。 如果是有名的,那么create的时候,如果有名的已经存在,则返回之前的相应的句柄。​ 另外需要注意的就是注意等待的副作用,如果是自动重置,可能wait触发之后会reset. 关于函数pulseEvent 函数功能:将事件触发后立即将事件设置为未触发,相当于触发一个事件脉冲。 函数原型:BOOLPulseEvent(HANDLEhEvent); 函数说明:这是一个不常用的事件函数,此函数相当于SetEvent()后立即调用ResetEvent();此时情况可以分为两种: 1.对于手动置位事件,所有正处于等待状态下线程都变成可调度状态。 2.对于自动置位事件,所有正处于等待状态下线程只有一个变成可调度状态。 此后事件是末触发的。该函数不稳定,因为无法预知在调用PulseEvent ()时哪些线程正处于等待状态。 ​ 如何理解,可以理解为一个脉冲,只解放当时在等待的那些,而之后的就不在考虑了。 一个简答的例子解释: 触发一个事件脉冲PulseEvent ()写一个例子,主线程启动7个子线程,其中有5个线程Sleep(10)后对一事件调用等待函数(称为快线程),
    另有2个线程Sleep(100)后也对该事件调用等待函数(称为慢线程)。主线程启动所有子线程后再Sleep(50)保证有5个快线程都正处于等待状态中。
    此时若主线程触发一个事件脉冲,那么对于手动置位事件,这5个线程都将顺利执行下去。对于自动置位事件,这5个线程中会有中一个顺利执行下去。
    而不论手动置位事件还是自动置位事件,那2个慢线程由于Sleep(100)所以会错过事件脉冲,因此慢线程都会进入等待状态而无法顺利执行下去。​ http://blog.sina.com.cn/s/blog_c33b15000102x3oa.html
  • 相关阅读:
    TestNG中DataProvider的用法
    性能调优过程发现的问题
    20170221——接口自动化测试代码提交流程
    svn忽略target文件
    springboot搭建dubbo+zookeeper简单案例
    docker上启动mysql镜像,mysq中记录乱码解决方法
    docker在linux上的安装
    使用jave1.0.2将amr文件转成其他格式报错解决方案
    使用fio命令查看磁盘iops
    解决使用maven clean项目的时候报错,删除target文件夹失败
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/4677664.html
Copyright © 2011-2022 走看看