C++多线程同步之事件(Event)
原文链接:http://blog.csdn.net/olansefengye1/article/details/53291074
一、事件(Event)原理解析
1、线程同步Event,主要用于线程间的等待通知。
2、内核对象中,事件内核对象是个最基本的对象。
3、事件包含一个使用计数(与所有内核对象一样),一个用于指明该事件是个自动重置的事件还是人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
4、事件能够通知一个操作已经完成。
5、有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
6、当一个线程执行初始化操作,然后通知另一个线程执行剩余的操作时,事件使用得最多。
7、事件初始化为未通知状态,然后,当该线程完成它的初始化操作后,它就将事件设置为已通知状态。这时,一直在等待该事件的另一个线程发现该事件已经得到通知,因此它就变成可调度线程。
二、Win32平台源码
1、相关头文件及API
函数名 | 函数说明 |
---|---|
CreateEvent | Creates or opens a named or unnamed event object. |
CreateEventEx | Creates or opens a named or unnamed event object and returns a handle to the object. |
OpenEvent | Opens an existing named event object. |
PulseEvent | Sets the specified event object to the signaled state and then resets it to the nonsignaled state after releasing the appropriate number of waiting threads. |
ResetEvent | Sets the specified event object to the nonsignaled state. |
SetEvent | Sets the specified event object to the signaled state. |
/*头文件*/
#include<windows.h>
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTESlpEventAttributes, // 安全属性
BOOLbManualReset, // 复位方式
BOOLbInitialState, // 初始状态
LPCTSTRlpName // 对象名称
);
参数:
lpEventAttributes[In]: 一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。Windows NT/2000:lpEventAttributes的结构中的成员为新的事件指定了一个安全符。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。
bManualReset[In]: 指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当事件被一个等待线程释放以后,系统将会自动将事件状态复原为无信号状态。
bInitialState[In]: 指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。
lpName[In]:指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。 如果lpName指定的名字,与一个存在的命名的事件对象的名称相同,函数将请求EVENT_ALL_ACCESS来访问存在的对象。这时候,由于bManualReset和bInitialState参数已经在创建事件的进程中设置,这两个参数将被忽略。如果lpEventAttributes是参数不是NULL,它将确定此句柄是否可以被继承,但是其安全描述符成员将被忽略。 如果lpName为NULL,将创建一个无名的事件对象。 如果lpName的和一个存在的信号、互斥、等待计时器、作业或者是文件映射对象名称相同,函数将会失败,在GetLastError函数中将返回ERROR_INVALID_HANDLE。造成这种现象的原因是这些对象共享同一个命名空间。
返回值:如果函数调用成功,函数返回事件对象的句柄。如果对于命名的对象,在函数调用前已经被创建,函数将返回存在的事件对象的句柄,而且在GetLastError函数中返回ERROR_ALREADY_EXISTS。如果函数失败,函数返回值为NULL,如果需要获得详细的错误信息,需要调用GetLastError。
HANDLE WINAPI CreateEventEx(
__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,
__in_opt LPCTSTR lpName,
__in DWORD dwFlags,
__in DWORD dwDesiredAccess
);
参数:
lpEventAttributes[in, optional] :一个指向SECURITY_ATTRIBUTES结构的指针,如果该参数设为NULL,那么事件内核对象的句柄不能被子进程继承.
lpName[in, optional] :指向事件内核对象的名称字符串的指针,如果该参数设为NULL,那么这个对象被创建为一个匿名事件内核对象.
dwFlags[in] :这个参数可被设为以下一个或多个值:CREATE_ EVENT_ INITIAL_ SET 0x00000002 表示对象初始状态为已触发,否则为未触发;CREATE_ EVENT_ MANUAL_RESET 0x00000001 表示这个事件对象必须用ResetEvents函数手动重置,如果不设置这个标志,系统会在内核对象被释放后自动重置.
dwDesiredAccess[in] :访问权限描述标记。
返回值:如果函数调用成功,返值是所创建或打开的事件内核对象的句柄.如果调用失败则返回NULL。
HANDLE OpenEvent(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
参数说明:
dwDesiredAccess [in]:指定对事件对象的请求访问权限,如果安全描述符指定的对象不允许要求通过对调用该函数的过程,函数将返回失败。该参数必须设置为以下值:EVENT_ALL_ACCESS 指定事件对象所有可能的权限。
bInheritHandle [in]:指定是否返回的句柄是否继承 。该参数必须设置为false。
lpName[in]:指向一个以null结束的字符串,即将要打开的事件对象的名字。名称是区分大小写的。
返回值:函数执行成功则返回事件对象的句柄;失败则返回NULL,获取错误信息可以使用GetLastError。
DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle,
__in DWORD dwMilliseconds
);
参数:
hHandle[in]:对象句柄。可以指定一系列的对象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。
dwMilliseconds[in]:定时时间间隔,单位为milliseconds(毫秒).如果指定一个非零值,函数处于等待状态直到hHandle标记的对象被触发,或者时间到了。如果dwMilliseconds为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。如果dwMilliseconds为INFINITE,对象被触发信号后,函数才会返回。
DWORD WaitForMultipleObjects(
DWORD nCount, // number of handles in the handle array
CONST HANDLE *lpHandles, // pointer to the object-handle array
BOOL fWaitAll, // wait flag
DWORD dwMilliseconds // time-out interval in milliseconds
);
参数:
nCount: 句柄的数量 最大值为MAXIMUM_WAIT_OBJECTS(64)
HANDLE: 句柄数组的指针。 HANDLE 类型可以为(Event,Mutex,Process,Thread,Semaphore )数组 。
BOOL bWaitAll: 等待的类型,如果为TRUE 则等待所有信号量有效在往下执行,FALSE 当有其中一个信号量有效时就向下执行。
DWORD dwMilliseconds: 超时时间 超时后向执行。 如果为WSA_INFINITE 永不超时。如果没有信号量就会在这死等。
另外:
一个Event被创建以后,可以用OpenEvent()**API来获得它的Handle,用**CloseHandle() 来关闭它,用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent() 来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待 其变为有信号。
PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event 对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的. 对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于 人工复位的Event对象,它释放所有等待的thread.
3、Win32源码
/************************MyEvent.h******************************/
#ifndef _MY_EVENT_H
#define _MY_EVENT_H
#include <windows.h>
class CMyEvent
{
public:
CMyEvent()
{
m_hEvent = CreateEvent(NULL /*安全属性指针*/
, false /*复位方式*/
, true /*初始化状态*/
, NULL /*事件名称*/
);
if(NULL == m_hEvent)
{
return;
}
}
~CMyEvent()
{
CloseHandle(m_hEvent);
}
void Lock()
{
WaitForSingleObject(m_hEvent,INFINITE);
}
void UnLock()
{
SetEvent(m_hEvent);
}
private:
HANDLE m_hEvent;
};
class CEventAutoLock
{
public:
CEventAutoLock(CMyEvent* pMyEvent)
: m_pMyEvent(pMyEvent)
{
if(NULL != m_pMyEvent)
{
m_pMyEvent->Lock();
}
}
~CEventAutoLock()
{
m_pMyEvent->UnLock();
}
private:
CMyEvent *m_pMyEvent;
};
#endif
/****************************main.cpp****************************/
#include <iostream>
#include <windows.h>
#include "MySemaphore.h"
#include "MyMutex.h"
#include "MyCriticalSection.h"
#include "MyEvent.h"
using namespace std;
CMySemaphore g_MySemaphore; //信号量
CMyMutex g_MyMutex; //互斥量
CMyCriticalSection g_MyCriticalSection; //临界区
CMyEvent g_MyEvent; //事件
DWORD WINAPI Fun(LPVOID lpParamter)
{
string strPrint((const char*)lpParamter);
int iRunTime = 0;
//执行100次跳出
while(++iRunTime<10)
{
{
CEventAutoLock clock(&g_MyEvent);
cout <<"["<< iRunTime <<"]:"<< strPrint.c_str()<<endl;
}
}
return 0;
}
int main()
{
//创建五个子线程
string str1 = "A";
string str2 = "B";
string str3 = "C";
string str4 = "D";
string str5 = "E";
HANDLE hThread1 = CreateThread(NULL, 0, Fun, (void*)str1.c_str(), 0, NULL);
HANDLE hThread2 = CreateThread(NULL, 0, Fun, (void*)str2.c_str(), 0, NULL);
HANDLE hThread3 = CreateThread(NULL, 0, Fun, (void*)str3.c_str(), 0, NULL);
HANDLE hThread4 = CreateThread(NULL, 0, Fun, (void*)str4.c_str(), 0, NULL);
HANDLE hThread5 = CreateThread(NULL, 0, Fun, (void*)str5.c_str(), 0, NULL);
//关闭线程
CloseHandle(hThread1);
CloseHandle(hThread2);
CloseHandle(hThread3);
CloseHandle(hThread4);
CloseHandle(hThread5);
getchar();
// system("pause");
return 0;
}
执行结果:
Linux平台
在Linux平台下没有专门的Event(事件)对象,可以依靠Mutex实现和Event相同的功能。Mutex的使用可参见我前面的博客。
C++多线程同步之事件(Event)的更多相关文章
- 并发编程~~~多线程~~~线程queue, 事件event,
一 线程queue 多线程抢占资源,只能让其串行. 互斥锁 队列 import queue q = queue.Queue() # 先进先出 q = queue.LifoQueue() # 先进后出 ...
- [b0041] python 归纳 (二六)_多进程数据共享和同步_事件Event
# -*- coding: utf-8 -*- """ 多进程 同步 事件multiprocessing.Event 逻辑: 子线程负责打印,会阻塞, 等待主进程发出控制 ...
- 多线程(五)多线程同步_Event事件
事件和互斥体同样属于内核同步对象,它和互斥体以及临界区在功能上有以下区别 前面的互斥体和临界区主要作用在于确保控制多个线程之间对共享资源访问,保证共享资源的完整性 事件主要作用是通知其它线程一个操作己 ...
- MFC线程(三):线程同步事件(event)与互斥(mutex)
前面讲了临界区可以用来达到线程同步.而事件(event)与互斥(mutex)也同样可以做到. Win32 API中的线程事件 HANDLE hEvent = NULL; void MainTestFu ...
- [一个经典的多线程同步问题]解决方案二:Event事件
使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权”特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题. 首先介绍下如何使用事件.事件E ...
- 多线程面试题系列(6):经典线程同步 事件Event
上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的"线程所有权"特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题.首先 ...
- 秒杀多线程第六篇 经典线程同步 事件Event
原文地址:http://blog.csdn.net/morewindows/article/details/7445233 上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权” ...
- 转--- 秒杀多线程第六篇 经典线程同步 事件Event
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题 ...
- C#多线程同步事件及等待句柄AutoResetEvent 和 ManualResetEvent
最近捣鼓了一下多线程的同步问题,发现其实C#关于多线程同步事件处理还是很灵活,这里主要写一下,自己测试的一些代码,涉及到了AutoResetEvent 和 ManualResetEvent,当然还有也 ...
随机推荐
- promise的生命周期
每个promise都会经历一个短暂的生命周期: 先是处于进行中(pending)状态,此时操作并未完成,所以他也是未处理的(unsettled): 一旦异步惭怍执行结束,promise则 变为已处理( ...
- SWIFT中切換UIContainerView內的Controller
如下,一个UIContainerView内切换两个Controller,当点击登录的时候UIContainerView的视图为LoginController,当点击登记的时候UIContainerVi ...
- SWIFT Optional Value
SWIFT中有一个类型定义叫可选值,在变量类型后面加一个?号即可定义一个类型为Optional Value的变量,当在使用变量时要用到强制解包!. 如在页面上有一个可选输入年龄的框,在接受数据的时间就 ...
- shell 脚本实战笔记(2)--环境变量PATH的恩怨情仇
在linux环境下, 相信大家对环境变量PATH, 多多少少有所接触, 这边讲讲PATH的在linux的前世因缘. 先讲讲一个列子 假如我们在为一个新的应用配置其PATH路径中时, 不小心忽略了原先 ...
- nib must contain exactly one top level object which must be a UICollectionReusableView instance
多了一个
- 8个iPhone防盗秘籍 为手机和资料安全保驾护航
最近发现用x手机的朋友越来越多,今天一个朋友手机被偷,万分焦急,失财事小,电话里很多手机号码等重要信息都无法找回.为了让大家尽量安全使用自己的iPhone或苹果产品,哪怕丢失后也有最大的可能性找回,特 ...
- Spring的事件发布机制
一:Spring的事件发布 ApplicationContext提供了针对Bean的事件传播功能,其中的主角是publishEvent()方法,通过这个方法可以将事件通知给系统内的监听器(需实现App ...
- 杭电oj2001-C语言
题目 题目 Problem Description 输入两点坐标(X1,Y1),(X2,Y2),计算并输出两点间的距离. Input 输入数据有多组,每组占一行,由4个实数组成,分别表示x1,y1,x ...
- cf 557D 二分图黑白染色
题意:给出一个 n 点 m 边的图,问最少加多少边使其能够存在奇环,加最少边的情况数有多少种 奇环和偶环其实就是二分图的性质:二分图不存在奇环,所以只要判断这张图是否是二分图就行了: 如果本身就不是二 ...
- HDU6387 AraBellaC
题意 AraBellaC Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Tota ...