




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
一、 简介1、 事件对象事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。2、 关键代码段关键代码段(临界区)工作在用户方式下。关键代码段(临界区)是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权。3、 线程死锁哲学家进餐的问题线程1拥有了临界区对象A,等待临界区对象B的拥有权,线程2拥有了临界区对象B,等待临界区对象A的拥有权,就造成了死锁。4、 互斥对象、事件对象与关键代码段的比较互斥对象和事件对象属于内核对象,利用内核对象进行线程同步,速度较慢,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个线程间进行同步。关键代码段是工作在用户方式下,同步速度较快,但在使用关键代码段时,很容易进入死锁状态,因为在等待进入关键代码段时无法设定超时值。5、 基于消息的异步套接字Windows套接字在两种模式下执行I/O操作,阻塞和非阻塞。在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(将控制权交还给程序)。而在非阻塞模式下,Winsock函数无论如何都会立即返回。Windows Sockets为了支持Windows消息驱动机制,使应用程序开发者能够方便地处理网络通信,它对网络事件采用了基于消息的异步存取策略。Windows Sockets的异步选择函数WSAAsyncSelect()提供了消息机制的网络事件选择,当使用它登记的网络事件发生时,Windows应用程序相应的窗口函数将收到一个消息,消息中指示了发生的网络事件,以及与事件相关的一些信息。二、 代码举例1、事件对象#include #include DWORD WINAPI Fun1Proc( LPVOID lpParameter / thread data);DWORD WINAPI Fun2Proc( LPVOID lpParameter / thread data);int tickets=100;HANDLE g_hEvent;void main()HANDLE hThread1;HANDLE hThread2;hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);/g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);g_hEvent=CreateEvent(NULL,FALSE,FALSE,tickets);if(g_hEvent)if(ERROR_ALREADY_EXISTS=GetLastError()coutonly instance can run!0)Sleep(1);coutthread1 sell ticket : tickets-0)Sleep(1);coutthread2 sell ticket : tickets-endl;elsebreak;SetEvent(g_hEvent);return 0;2、关键代码段#include #include DWORD WINAPI Fun1Proc( LPVOID lpParameter / thread data);DWORD WINAPI Fun2Proc( LPVOID lpParameter / thread data);int tickets=100;CRITICAL_SECTION g_csA;CRITICAL_SECTION g_csB;void main()HANDLE hThread1;HANDLE hThread2;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(4000);DeleteCriticalSection(&g_csA);DeleteCriticalSection(&g_csB);DWORD WINAPI Fun1Proc( LPVOID lpParameter / thread data)while(TRUE)EnterCriticalSection(&g_csA);Sleep(1);EnterCriticalSection(&g_csB);if(tickets0)Sleep(1);coutthread1 sell ticket : tickets-0)Sleep(1);coutthread2 sell ticket : tickets-endl;elsebreak;LeaveCriticalSection(&g_csA);LeaveCriticalSection(&g_csB);coutthread2 is running!endl;return 0;三、 各函数说明1、CreateEvent函数该函数创建或打开一个命名的或无名的事件对象函数原型:HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,/ 安全属性BOOL bManualReset,/ 复位方式BOOL bInitialState,/ 初始状态LPCTSTR lpName / 对象名称);参数lpEventAttributes:输入一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。Windows NT/2000:lpEventAttributes的结构中的成员为新的事件指定了一个安全符。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。bManualReset:输入指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当事件被一个等待线程释放以后,系统将会自动将事件状态复原为无信号状态。bInitialState:输入指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。lpName:输入指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。如果lpName指定的名字,与一个存在的命名的事件对象的名称相同,函数将请求EVENT_ALL_ACCESS来访问存在的对象。这时候,由于bManualReset和bInitialState参数已经在创建事件的进程中设置,这两个参数将被忽略。如果lpEventAttributes是参数不是NULL,它将确定此句柄是否可以被继承,但是其安全描述符成员将被忽略。如果lpName为NULL,将创建一个无名的事件对象。如果lpName的和一个存在的信号、互斥、等待计时器、作业或者是文件映射对象名称相同,函数将会失败,在GetLastError函数中将返回ERROR_INVALID_HANDLE。造成这种现象的原因是这些对象共享同一个命名空间。终端服务(Terminal Services):名称中可以加入Global或是Local的前缀,这样可以明确的将对象创建在全局的或事务的命名空间。名称的其它部分除了反斜杠(),可以使用任意字符。详细内容可参考Kernel Object Name Spaces。Windows 2000:在Windows 2000系统中,没有终端服务运行,Global和Local前缀将被忽略。名称的其它部分除了反斜杠(),可以使用任意字符。Windows NT 4.0以及早期版本,Windows 95/98:名称中除了反斜杠(),可以使用任意字符。返回值如果函数调用成功,函数返回事件对象的句柄。如果对于命名的对象,在函数调用前已经被创建,函数将返回存在的事件对象的句柄,而且在GetLastError函数中返回ERROR_ALREADY_ESTS。如果函数失败,函数返回值为NULL,如果需要获得详细的错误信息,需要调用GetLastError。备注调用CreateEvent函数返回的句柄,该句柄具有EVENT_ALL_ACCESS权限去访问新的事件对象,同时它可以在任何有此事件对象句柄的函数中使用。在调用的过程中,所有线程都可以在一个等待函数中指定事件对象句柄。当指定的对象的状态被置为有信号状态时,单对象等待函数将返回。对于多对象等待函数,可以指定为任意或所有指定的对象被置为有信号状态。当等待函数返回时,等待线程将被释放去继续运行。初始状态在bInitialState参数中进行设置。使用SetEvent函数将事件对象的状态置为有信号状态。使用ResetEvent函数将事件对象的状态置为无信号状态。当一个手动复原的事件对象的状态被置为有信号状态时,该对象状态将一直保持有信号状态,直至明确调用ResetEvent函数将其置为无符号状态。当事件的对象被置为有信号状态时,任意数量的等待中线程,以及随后开始等待的线程均会被释放。当一个自动复原的事件对象的状态被置为有信号状态时,该对象状态将一直保持有信号状态,直至一个等待线程被释放;系统将自动将此函数置为无符号状态。如果没有等待线程正在等待,事件对象的状态将保持有信号状态。多个进程可持有同一个事件对象的多个句柄,可以通过使用此对象来实现进程间的同步。下面的对象共享机制是可行的:在CreateEvent函数中,lpEventAttributes参数指定句柄可被继承时,通过CreateProcess函数创建的子进程继承的事件对象句柄。一个进程可以在DuplicateHandle函数中指定事件对象句柄,从而获得一个复制的句柄,此句柄可以被其它进程使用。一个进程可以在OpenEvent或CreateEvent函数中指定一个名字,从而获得一个有名的事件对象句柄。使用CloseHandle函数关闭句柄。当进程停止时,系统将自动关闭句柄。当最后一个句柄被关闭后,事件对象将被销毁。2、SetEvent函数函数原型:BOOL SetEvent(HANDLE hEvent);其中hEvent表示句柄,返回值:如果操作成功,则返回非零值,否则为0。说明:设置事件的状态为有标记,释放任意等待线程。如果事件是手工的,此事件将保持有标记直到调用ResetEvent。这种情况下将释放多个线程,如果事件是自动的,此事件将保持有标记,直到一个线程被释放,系统将设置事件的状态为无标记。如果没有线程在等待,则此事件将保持有标记,直到一个线程被释放。3、线程中SetEvent及WaitForSingleObject用法SetEvent/ResetEvent分别将EVENT置为这两种状态分别是发信号与不发信号。WaitForSingleObject()等待,直到参数所指定的OBJECT成为发信号状态时才返回,OBJECT可以是EVENT,也可以是其它内核对象。 当你创建一个线程时,其实那个线程是一个循环,不像上面那样只运行一次的。这样就带来了一个问题,在那个死循环里要找到合适的条件退出那个死循环,那么是怎么样实现它的呢?在Windows里往往是采用事件的方式,当然还可以采用其它的方式。在这里先介绍采用事件的方式来通知从线程运行函数退出来,它的实现原理是这样,在那个死循环里不断地使用WaitForSingleObject函数来检查事件是否满足,如果满足就退出线程,不满足就继续运行。当在线程里运行阻塞的函数时,就需要在退出线程时,先要把阻塞状态变成非阻塞状态,比如使用一个线程去接收网络数据,同时使用阻塞的SOCKET时,那么要先关闭SOCKET,再发送事件信号,才可以退出线程的。当然我感觉重要应用方面还是用来锁定,实现所谓的pv功能。在调用的过程中,所有线程都可以在一个等待函数中指定事件对象句柄。当指定的对象的状态被置为有信号状态时,单对象等待函数将返回。对于多对象等待函数,可以指定为任意或所有指定的对象被置为有信号状态。当等待函数返回时,等待线程将被释放去继续运行。初始状态在bInitialState参数中进行设置。使用SetEvent函数将事件对象的状态置为有信号状态。使用ResetEvent函数将事件对象的状态置为无信号状态。当一个手动复原的事件对象的状态被置为有信号状态时,该对象状态将一直保持有信号状态,直至明确调用ResetEvent函数将其置为无符号状态。当事件的对象被置为有信号状态时,任意数量的等待中线程,以及随后开始等待的线程均会被释放。当一个自动复原的事件对象的状态被置为有信号状态时,该对象状态将一直保持有信号状态,直至一个等待线程被释放;系统将自动将此函数置为无符号状态。如果没有等待线程正在等待,事件对象的状态将保持有信号状态。多个进程可持有同一个事件对象的多个句柄,可以通过使用此对象来实现进程间的同步。下面的对象共享机制是可行的:在CreateEvent函数中,lpEventAttributes参数指定句柄可被继承时,通过CreateProcess函数创建的子进程继承的事件对象句柄。一个进程可以在DuplicateHandle函数中指定事件对象句柄,从而获得一个复制的句柄,此句柄可以被其它进程使用。一个进程可以在OpenEvent或CreateEvent函数中指定一个名字,从而获得一个有名的事件对象句柄。使用CloseHandle函数关闭句柄。当进程停止时,系统将自动关闭句柄。当最后一个句柄被关闭后,事件对象将被销毁。4、ResetEvent函数这个函数把指定的事件对象设置为无信号状态。函数原型:BOOL ResetEvent ( HANDLE hEvent );参数说明:hEventin 指向事件对象的句柄.由 CreateEvent orOpenEvent函数返回。 这个句柄需要拥有EVENT_MODIFY_STATE 访问权限.函数成功,返回非0值,否则返回0值,可以调用GetLastError得到错误的详细信息。备注:一个事件对象一直都保持在无信号状态,直到显式调用 SetEvent or PulseEvent 函数把它设置到有信号状态。 这些无信号的事件对象会阻塞任何在内部调用wait函数的线程。这个函数用于手动重置的事件对象。手动重置的对象在线程释放后必须手动置为无信号状态。 自动重置的事件对象在一个等待它成功的线程释放后会自动变为无信号状态。重置一个无信号的事件对象没有任何效果。6、 InitializeCriticalSection函数该函数初始化一个临界资源对象。函数原型:VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection / critical section);参数值:lpCriticalSection临界资源对象指针。备注:单进程的线程可以使用临界资源对象来解决同步互斥问题,该对象不能保证哪个线程能够获得到临界资源对象,因而该系统能公平的对待每一个线程。7、 DeleteCriticalSection函数函数原型:void WINAPI DeleteCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection);参数:lpCriticalSection对关键节对象的指针。先前必须已将该对象初始化与InitializeCriticalSection函数中。备注:删除关键节对象释放由该对象使用的所有系统资源。关键节之后,对象已被删除,未引用的对象的任何功能,在关键节 (如EnterCriticalSection、TryEnterCriticalSection、 和LeaveCriticalSection) 上运行非InitializeCriticalSection和InitializeCriticalSectionAndSpinCount。如果您尝试这样做,可能会出现内存损坏和其他意外的错误。如果它仍拥有删除关键节,则已删除的关键节的所有权在等待的线程的状态未定义。8、 EnterCriticalSection函数和LeaveCriticalSection函数函数原型:VOID EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection );VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection );说明:多个线程操作相同的数据时,一般是需要按顺序访问的,否则会引导数据错乱,无法控制数据,变成随机变量。为解决这个问题,就需要引入互斥变量,让每个线程都按顺序地访问变量。这样就需要使用EnterCriticalSection和LeaveCriticalSection函数。9、 WSAAsyncSelect函数本函数用来请求Windows Sockets DLL为窗口句柄发一条消息无论它何时检测到由lEvent参数指明的网络事件.要发送的消息由wMsg参数标明.被通知的套接口由s标识.本函数自动将套接口设置为非阻塞模式.函数原型:int WSAAsyncSelect( SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent );参数说明:s 标识一个需要事件通知的套接口的描述符.hWnd 标识一个在网络事件发生时需要接收消息的窗口句柄.wMsg 在网络事件发生时要接收的消息.lEvent位屏蔽码,用于指明应用程序感兴趣的网络事件集合10、WSAEnumProtocols函数函数原型:int WSAEnumProtocols( LPINT lpiProtocols, LPWSAPROTOCOL_INFO lpProtocolBuffer, ILPDWORD lpdwBufferLength );说明:Win32平台支持多种不同的网络协议,采用Winsock2,就可以编写可直接使用任何一种协议的网络应用程序了。通过WSAEnumProtocols函数可以获得系统中安装的网络协议的相关信息。参数:lpiProtocols,一个以NULL结尾的协议标识号数组。这个参数是可选的,如果lpiProtocols为NULL,则返回所有可用协议的信息,否则,只返回数组中列出的协议信息。lpProtocolBuffer,out,一个用WSAPROTOCOL_INFO结构体填充的缓冲区。 WSAPROTOCOL_INFO结构体用来存放或得到一个指定协议的完整信息。lpdwBufferLength,in, out,在输入时,指定传递给WSAEnumProtocols()函数的lpProtocolBuffer缓冲区的长度;在输出时,存有获取所有请求信息需传递给WSAEnumProtocols ()函数的最小缓冲区长度。这个函数不能重复调用,传入的缓冲区必须足够大以便能存放所有的元素。这个规定降低了该函数的复杂度,并且由于一个 机器上装载的协议数目往往是很少的,所以并不会产生问题。12、WSASocket函数函数原型:SOCKET WSASocket( int af, int type, int protocol, LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags );参数:前三个参数和socket()函数的前三个参数含义一样。lpProtocolInfo,一个指向WSAPROTOCOL_INFO结构体的指针,该结构定义了所创建的套接字的特性。如果lpProtocolInfo为NULL,则WinSock2 DLL使用前三个参数来决定使用哪一个服务提供者,它选择能够支持规定的地址族、套接字类型和协议值的第一个传输提供者。如果lpProtocolInfo不为NULL,则套接字绑定到与指定的结构WSAPROTOCOL_INFO相关的提供者。g,保留的。dwFlags,套接字属性的描述。13、WSARecvFrom函数函数原型:int WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct sockaddr FAR *lpFrom, LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 部编人教版三年级语文下册《习作:身边那些有特点的人》公开课教学课件
- 能否取消拍卖合同协议书
- 物业合同续签申请协议书
- 电力器材回收合同协议书
- 材料被盗调解协议书模板
- 碎石机加工样本合同协议
- 门店客户股东合伙协议书
- 高档小区房屋置换协议书
- 物业旧物回收合同协议书
- 聘用兼职人员协议书范本
- JBT 5300-2024 工业用阀门材料 选用指南(正式版)
- 2024年苏州历史文化名城建设集团有限公司招聘笔试冲刺题(带答案解析)
- 汽车底盘DFMEA-减震器总成
- (2024年)诊疗规范培训课件
- 2024年广东汕头市投资控股集团有限公司招聘笔试参考题库含答案解析
- 盐城市2022-2023学年七年级下学期数学期末试卷(含答案解析)
- 新版译林英语五年级上第一二单元测试含听力文本和答案
- 膝关节退行性变的护理
- 急性肺栓塞课件
- 洁净区臭氧消毒效果验证方案
- 停车场数据分析与管理
评论
0/150
提交评论