CEvent类祥解       我要收藏
2008-01-23 09:34:07
编辑 删除
CEvent类祥解
CEvent 类提供了对事件的支持。事件是一个允许一个线程在某种情况发生时,唤醒另外一个线程的同步对象。事件告诉线程何时去执行某一给定的任务,从而使多个线程流平滑。例如在某些网络应用程序中,一个线程(记为A)负责监听通信端口,另一个线程(记为B)负责更新用户数据。通过使用CEvent类,线程A可以通知线程B何时更新用户数据,这样线程B可以尽快地更新用户数据。每一个CEvent对象可以有两种状态:有信号状态(signaled)和无信号状态(nonsignaled)。线程监视位于其中的CEvent类对象的状态,并在相应的时候采取相应的操作。
    MFC中,CEvent类对象有两种类型,分别是所谓的人工事件和自动事件。对于自动事件,当其获得信号后,就会释放下一个可用的线程。一个自动 CEvent对象在被至少一个线程释放后会自动返回到无信号状态;而人工事件对象获得信号后,释放所有可利用线程,直到调用成员函数ReSetEvent ()将其设置为无信号状态时为止。注意,在创建CEvent类的对象时,默认创建的是自动事件。

CEvent的各成员函数的原型与参数说明如下。
CEvent(BOOL bInitiallyOwn = FALSE,
BOOL bManualReset = FALSE,
LPCTSTR lpszName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );
 

bInitiallyOwn:若bInitiallyOwnTRUE,则使CMultilock类对象和CSingleLock类对象的线程可用;否则,要访问资源的线程必须等待。该参数的默认值为FALSE
bManualReset:指定要创建的CEvent对象是属于手工事件还是自动事件。为TRUE,则为手工事件,否则为自动事件。该参数默认值为FALSE
lpszName:指定要创建的事件对象的名,如果该事件对象将跨进程使用,则此参数不能为NULL。如果该参数和一个已经存在的CEvent对象相同,则该构造函数返回一个对这个已存在对象的引用;如果参数和一个已存在的非CEvent类的同步对象(如CMutex)相同,则对象创建失败;
lpsaAttribute:指向SECURITY_ATTRIBUTES结构的指针,该参数决定要创建的事件对象的安全属性,一般置为NULL
在事件对象建成后,可以调用其成员函数来改变其状态。
BOOL CEvent::SetEvent ();
 

CEvent类对象的状态设置为有信号状态,并且释放所有等待的线程;如果该事件是人工事件,则CEvent类对象保持为有信号状态,直到调用成员函数ResetEvent()将其重新设为无信号状态时为止,这样该事件就可以释放多个线程;如果CEvent类对象为自动事件,则在SetEvent()将事件设置为有信号状态后,CEvent类对象由系统自动重置为无信号状态,除非一个线程被释放。
如果该函数执行成功,则返回非零值,否则返回零。
BOOL CEvent::ResetEvent();
 

该函数将事件的状态设置为无信号状态,并保持该状态直至SetEvent()被调用时为止。由于自动事件是由系统自动重置,故自动事件不需要调用该函数。
如果该函数执行成功,返回非零值,否则返回非零。
BOOL CEvent::PulseEvent()
 

发送一个事件脉冲,该函数完成一系列操作后才返回。对于自动事件,PulseEvent()将事件设置为有信号状态,等待一个线程被释放,将事件重置为无信号状态,然后PulseEvent()返回;对于人工事件,则将等待该事件的所有线程被释放,事件被自动重置为无信号状态,然后PulseEvent()返回。
一个CEvent对象在线程中被创建后,自动处于无信号状态,但在另一个线程中可以调用Win32 API WaitForSingleObject()函数来监视其状态。
该函数的原型及参数说明如下:
DWORD WaitForSingleObject(HANDLE hHandleDWORD dwMilliseconds);
 
其中hHandle为指向要监视的同步对象的句柄,dwMilliseconds为监视hHandle所指向的对象所设置的超时值,单位为毫秒。当在线程的执行函数中调用该函数时,线程暂时挂起,系统监视hHandle所指向的对象的状态。
如果经过dwMilliseconds毫秒后,hHandle指向的对象变为有信号状态,则WaitForSingleObject()返回,线程被释放,且返回值为WAIT_TIMEOUT
如果在挂起的dwMilliseconds毫秒内,线程所等待的对象在某一时刻变为有信号,则该函数立即返回,返回值为WAIT_OBJECT_0
参数dwMilliseconds有两个具有特殊意义的值:0INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。如果CEvent对象为自动事件,则当WaitForSingleObject(hHandle,INFINITE)返回时,自动把CEvent对象重置为无信号状态。CEvent::SetEvent()把对象设置为有信号状态,释放等待的线程。CEvent::ResetEvent()把对象设置为无信号状态,程序在waitforsingleobject函数WaitForSingleObject(hHandle,INFINITE)处等待。
 
例程9 MultiThread9
建立一个基于对话框的工程MultiThread9,在对话框IDD_MULTITHREAD9_DIALOG中加入一个按钮和两个编辑框控件,按钮的IDIDC_WRITEW,标题为'W’”;两个编辑框的ID分别为IDC_WIDC_D,属性都选中Read-only;
MultiThread9Dlg.h文件中声明两个线程函数:
UINT WriteW(LPVOID pParam);
UINT WriteD(LPVOID pParam);
使用ClassWizard分别给IDC_WIDC_D添加CEdit类变量m_ctrlWm_ctrlD
MultiThread9Dlg.cpp文件中添加如下内容:
为了文件中能够正确使用同步类,在文件开头添加
#include "afxmt.h"
定义事件对象和一个字符数组,为了能够在不同线程间使用,定义为全局变量。
CEvent eventWriteD;
char g_Array[10];
添加线程函数:
UINT WriteW(LPVOID pParam)
{
 CEdit *pEdit=(CEdit*)pParam;
 pEdit->SetWindowText("");
 for(int i=0;i<10;i++)
 {
  g_Array[i]=''W'';
      pEdit->SetWindowText(g_Array);
  Sleep(1000);
 }
 eventWriteD.SetEvent();
 return 0;
}
UINT WriteD(LPVOID pParam)
{
 CEdit *pEdit=(CEdit*)pParam;
 pEdit->SetWindowText("");
 WaitForSingleObject(eventWriteD.m_hObject,INFINITE);
 for(int i=0;i<10;i++)
 {
  g_Array[i]=''D'';
      pEdit->SetWindowText(g_Array);
  Sleep(1000);
 }
 return 0;
}
  仔细分析这两个线程函数, 您就会正确理解CEvent 类。线程WriteD执行到 WaitForSingleObject(eventWriteD.m_hObject,INFINITE);处等待,直到事件eventWriteD为有信号该线程才往下执行,因为eventWriteD对象是自动事件,则当WaitForSingleObject()返回时,系统自动把eventWriteD对象重置为无信号状态。
双击按钮IDC_WRITEW,添加其响应函数:
void CMultiThread9Dlg::OnWritew()
{
 CWinThread *pWriteW=AfxBeginThread(WriteW,
  &m_ctrlW,
  THREAD_PRIORITY_NORMAL,
  0,
  CREATE_SUSPENDED);
 pWriteW->ResumeThread();
 CWinThread *pWriteD=AfxBeginThread(WriteD,
  &m_ctrlD,
  THREAD_PRIORITY_NORMAL,
  0,
  CREATE_SUSPENDED);
 pWriteD->ResumeThread();
 
}编译并运行程序,单击'W’”按钮,体会事件对象的作用。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。