本篇介绍使用事件。
事件是一种可用于同步的对象。一个事件对象可以有两种状态:有信号状态和无信号状态。
在MFC中,通过CEvent 类实现对事件的支持。一个CEvent对象在刚建立时可以设置有信号或无信号状态。默认是无信号状态。
CEvent对象有两种类型:人工事件和自动事件。在创建CEvent 类的对象时,默认创建的是自动事件。
一个自动CEvent 对象在被至少一个线程释放后会自动返回到无信号状态;
而人工事件对象获得信号后,释放可利用线程,但直到调用成员函数ResetEvent()才将其设置为无信号状态。
CEvent 类的各成员函数的原型和参数说明如下:
1. CEvent( BOOL bInitiallyOwn=FALSE,
BOOL bManualReset=FALSE,
LPCTSTR lpszName=NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute=NULL);
bInitiallyOwn:指定事件对象初始化状态,TRUE为有信号,FALSE为无信号;
bManualReset:指定要创建的事件是属于人工事件还是自动事件。TRUE为人工事件,FALSE为自动事件;
后两个参数一般设为NULL,在此不作过多说明。
2. BOOL CEvent::SetEvent();
将 CEvent 类对象的状态设置为有信号状态。如果事件是人工事件,则 CEvent 类对象保持为有信号状态,直到调用成员函数ResetEvent()将其重新设为无信号状态时为止。
如果CEvent 类对象为自动事件,则在SetEvent()将事件设置为有信号状态后,CEvent 类对象由系统自动重置为无信号状态。
3. BOOL CEvent::ResetEvent()
该函数将事件的状态设置为无信号状态,并保持该状态直至SetEvent()被调用时为止。由于自动事件是由系统自动重置,故自动事件不需要调用该函数。
一般通过调用WaitForSingleObject函数来监视事件状态。
下面开始写程序:
1. 建立一个基于对话框的工程MultiThread9,在对话框IDD_MULTITHREAD9_DIALOG中加入一个按钮和两个编辑框控件,按钮的ID为IDC_WRITEW,标题为“写‘W’”;两个编辑框的ID分别为IDC_W和IDC_D,属性都选中Read-only;注意把编辑框拉长一点,以容得下10个字母。
2. 使用ClassWizard分别给IDC_W和IDC_D添加CEdit类变量m_ctrlW和m_ctrlD;
3. 在MultiThread9Dlg.h文件中声明两个线程函数:
UINT WriteW(LPVOID pParam);
UINT WriteD(LPVOID pParam);
4. 在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;
}
5. 双击按钮IDC_WRITEW,添加其响应函数:
void CMultiThread9Dlg::OnWritew()
{
// TODO: Add your control notification handler code here
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();
}
6. 编译、运行。
分析:
事件enventWriteD对象开始是无信号。单击按钮后建立两个线程WriteW和WriteD。
线程WriteD执行到 WaitForSingleObject(eventWriteD.m_hObject,INFINITE);处等待,直到事件eventWriteD为有信号该线程才往下执行。
线程WriteW在返回之前通过调用SetEvent将事件设置为有信号。WriteD函数就可以继续执行。
这个程序跟上一个很接近。因此同样可以在运行时查看任务管理器。
对于Windows事件的理解,可以参考以下MSDN的网页:
http://msdn.microsoft.com/library/windows/desktop/ms682655
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686915