CEvent( BOOL bInitiallyOwn = FALSE; BOOL bManualReset = FALSE;
LPCTSTR lpszName = NULL; LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );
4个参数含义如下:
bInitiallyOwn 布尔量。如果值是True,用于CMultilock和
CSingleLock对象的线程将被允许。如果值为False,所有希望访问资
源的线程必须等待。缺省值为False。
bManualReset 布尔量。如果值为True,则Event对象是手动对象。如
果值为False,则Event对象是自动对象。缺省值为True。
lpszName CEvent对象的名称。如果事件对象被多个进程使用时必须
提供一个名称。缺省值为NULL。
lpsaAttribute CEvent对象的安全属性,与在Win32中的
SECURITY_ATTRIBUTES 相同。
尽管CEvent的构造函数有4个参数,但是经常不加任何参数的创建缺
…………………………………………………………Page 646……………………………………………………………
省的对象。当CEvent对象被创建之后,它 自动的处在未通信状态。为
了使其处在通信状态,可以调用其成员函数SetEvent ,如下所
示:
threadStart。SetEvent();
在执行完上述语句之后,threadStart将处在其通信状态。你的线程
应当监视它,这样才能知道何时执行。线程是通过调用如下Windows
API函数WaitForSingleObject()来监视CEvent对象的,形式如下:
::WaitForSingleObject(threadStart。m_hObject; INFINITE);
预定义的常量INFINITE告诉WaitForSingleObject()直到指定的
CEvent对象处在通信状态时才返回。换句话说,如果你把
WaitForSingleObject()放在线程的开头,系统将挂起线程直到
CEvent对象处在通信状态。当主线程准备好后,你应当调用SetEvent
()函数。
一旦线程不再挂起,它就可以运行了。但是,如果此时你还想和线程
通信,线程必须监视下一个CEvent对象处在通信状态,故你需要再次
调用WaitForSingleObject()函数,此时需要将等待时间设置为0,如
下所示:
::WaitForSingleObject(threadend。m_hObject; 0);
在这种情况下,如果WaitForSingleObject()返回值为
WAIT_OBJECT_0;则CEvent对象处在通信状态。否则,CEvent对象处在
非通信状态。
下面的例子说明如何使用CEvent类在两个线程间通信。按照以下步骤
进行:
1。 在ThreadView。cpp 中#include 〃ThreadView。h〃语句后面加上
#include 〃afxmt。h〃。
2。 在ThreadView。cpp 中volatile int threadController语句后加上
下列语句:
CEvent threadStart;
CEvent threadEnd;
删除语句volatile int threadController。
…………………………………………………………Page 647……………………………………………………………
3。 用下面的代码更换ThreadProc()函数。
UINT ThreadProc(LPVOID param)
{
::WaitForSingleObject(threadStart。m_hObject; INFINITE);
::MessageBox((HWND)param; 〃Thread activated。〃; 〃Thread〃; MB_OK);
BOOL keepRunning = TRUE;
while (keepRunning)
{
int result = ::WaitForSingleObject(threadEnd。m_hObject; 0);
if (result == WAIT_OBJECT_0)
keepRunning = FALSE;
}
::PostMessage((HWND)param; WM_THREADENDED; 0; 0);
return 0;
}
4。 用下面的语句替换OnStartthread()函数中的内容。
threadStart。SetEvent();
5。 用下面的语句替换OnStopthread()函数中的内容。
threadEnd。SetEvent();
6。 使用ClassWizard为CthreadView处理WM_CREATE消息的函数
OnCreate(),并在TODO后面添加代码。OnCreate()函数如下所示:
int CThreadView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == …1)
return …1;
// TODO: Add your specialized creation code here
…………………………………………………………Page 648……………………………………………………………
HWND hWnd = GetSafeHwnd();
AfxBeginThread(ThreadProc; hWnd);
return 0;
}
编译并运行这个程序,新版本的程序运行起来和旧版本的程序一样,
但是,新版本的程序为了实现在主线程和次要线程间通信,既使用了
CEvent类,又使用了用户定义的Windows消息。
新版本的程序和旧版本的程序的一个大的不同在于次要线程在
OnCreate()函数中被启动。然而由于线程函数的第一行即调用
WaitForSingleObject(),所以此线程立即被挂起并且等待
threadStart处于通信状态。
当threadStart处在通信状态时,新线程显示消息框,然后进入while
循环。这个while循环继续执行直到threadEnd处在通信状态,然后线
程向主线程发送一个WM_THREADENDED消息并退出。因为此线程是在
OnCreate()函数中被创建的;一旦结束,不会被重新启动。
第三节 线程同步
使用多线程可以带来一些非常有趣的问题。例如,如何防止两个线程
在同一时间访问同一数据?例如,假设一个线程正在更新一个数据
集,而同时另外一个线程正在读取数据集,结果如何?第二个线程将
会读取到错误的数据,因为数据集中只有一部分元素被更新过。
保持在同一个进程内的线程工作协调一致称之为线程同步。Event对
象实际上就是线程同步的一种形式。在本节中,你将会学到三种使你
的多线程程序更安全的线程同步对象—critical section、互斥对象
(mutex)、信号量 (semaphore)。
(1) 使用Critical Section
Critical Section是一种保证在一个时间只有一个线程访问数据集的
非常简单的方法。当你使用Critical Section,你给了线程一个它们
必须共享的对象。任何拥有Critical Section对象的线程可以访问被
保护起来的数据。其它线程必须等待直到第一个线程释放了Critical
Section对象,此后其它线程可以按照顺序抢 占Critical Section对
…………………………………………………………Page 649……………………………………………………………
象,访问数据。
因为线程只有拥有Critical Section对象才能访问数据,而且在一个
时刻只有一个线程可以拥有Critical Section对象,所以决不会出现
一个时刻有多个线程访问数据。
为了在MFC程序中创建一个Critical Section对象,你应当创建
CcriticalSection类的对象,如下所示:
CCriticalSection criticalSection
然后,当程序代码准备访问你保护的数据时,你应当调用
CCriticalSection的成员函数Lock(),
criticalSection。Lock();
如果另外一个线程并没有拥有criticalSection,Lock()将
criticalSection给调用它的线程。这个线程便能够访问受保护的数
据,此后它调用CcriticalSection的成员函数Unlock() :
criticalSection。Unlock();
Unlock()释放了对criticalSection的拥有权,这样其它线程就可以
占有它并访问受保护的数据。
最好的方法是将数据放在线程安全类中。当你这样做后,你不用担心
在主线程中的线程同步,线程安全类会替你处理的。下面的类
CCountArray便是一个线程安全类。
以下是COUNTARRAY。H,CcountArray的头文件。
#include 〃afxmt。h〃
小说推荐
- C语言游戏编程从入门到精通(PDF格式)
- -Page 1-Page 2-Page 3-Page 4-Page 5-Page 6-Page 7-Page 8-Page 9-Page 10-Page 11-Page 12-Page 13-Page 14
- 其他
- 最新章:第4章
- JMS简明教程(PDF格式)
- -Page 1-JMS1.1规范中文版卫建军2007‐11‐22-Page 2
- 其他
- 最新章:第28章
- SQL语言艺术(PDF格式)
- -Page 1-SQLSSQQLL语言艺术内容介绍本书分为12章,每一章包含许多原则或准则,并通过举例的方式对原则进行解释说明。这些例子大多来自于实际案例,对九种SQL经典查询场景以及其性能影响讨论,非常便于实践,为你数据库应用维护人员阅读。资深 SQL 专家 Stéphane Faroult倾力打
- 其他
- 最新章:第27章
- 软件工程实践者的思想(PDF格式)
- -Page 1-大 道 至 简—软件工程实践者的思想周爱民(Aimingoo 著-Page 2-序2004 年 11 月初爱民(Aimingoo)第一次把他的书稿给我,我翻看了一下,第一反应讲的是感想。这不错,在技
- 其他
- 最新章:第26章
- asp基础实用教程(DOC格式)
- 目 录一、关于ASP二、ASP的新功能三、创建ASP页四、使用脚本语言五、使用变量和常量六、使用集合七、ASP内建对象八、向浏览器发送内容九、包含文件十、访问数据库十一、调试ASP脚本十二、维护ASP应用程序的安全一、关于ASP Active Server Pages(ASP)是服务器端脚本编写环境
- 其他
- 最新章:第17章
- Linux实用培训教程(PDF)
- -Page 1-rrktqt的个人空间 Linux实用培训教程第一部分 作者:红联Linux实用培训教程第一部分-共三部分解的Linux知识,循序渐进的介绍Linux相关知识,从入门到提高,希望对所有学习Linux的朋友都有帮助 红联Linux论坛是致力于Linux技术讨论的站点,目前网站收录的文章
- 其他
- 最新章:第42章
- php程序设计简明教程(DOC格式)
- -Page 1-PHP 程序设计简明教程PHP 讲义 第 1 页 共 90 页-Page 2-目录序 4第一章 PHP 简介 6
- 其他
- 最新章:第31章
- 路由器基本知识及应用实例(DOC格式)
- 第二章 路由器第一节 路由器发展概述自从1984年问世至今,路由器已经走过了近20年的快速技术发展历程。路由器的应用领域不断扩展、从单一的互通网关逐渐扩展到覆盖广域网、城域网乃至用户接入的各个领域。近年来,路由器早已逐渐脱离单纯用于企业网出口和互联的概念,开始成为运营网络和各种专用业务网络的核心设备
- 其他
- 最新章:第48章
- Java编程思想第4版[中文版](PDF格式)
- -Page 1-Page 2《Thinking In Java》中文版作者:Bruce Eckel主页:http/BruceEckel.编译:Trans Bot主页:http/memberease~transbot致谢-献给那些直到现在仍在孜孜不倦创造下一代计算机语言的人们!指导您利用万维网的语言进
- 其他
- 最新章:第295章