深入浅出MFC第2版(PDF格式)-第153部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
Good
2
全域变量X
3 1
执行线程B先完成其工作,设定了全域变量X,然后执行线程A才读取X。
?? 表示执行次序
??
图 14…6a race condition (good)
764
…………………………………………………………Page 827……………………………………………………………
14 MFC
第 章 多緒程式設計
执行线程A 执行线程B
Bad
2
全域变量X
1 3
执行线程A先执行并读取全域变量X,然后执行线程B才设定X。太迟了。
?? 表示执行次序
??
???? 圖 14…6b race condition (bad )
NULL 执行线程A 执行线程B
NULL
执行线程A在此等待
执行线程B在此等待
全域变量global1
全域变量global2
从NULL 改变为合 global 1
法的值 NULL 从NULL 改变为合
法的值
NULL
执行线程A在此提供
执行线程B在此提供
global 2
全域变量global2 全域变量global1
的值
的值
图14…7 死结 (deadlock)
765
…………………………………………………………Page 828……………………………………………………………
第篇 深入 MFC 程式設計
要解决这些问题,必须有办法协调各个执行线程的执行次序,让某个线程等待某个线程。
Windows 系统提供四种同步化机制,帮助程序进行这种工作:
1。 Critical Section (关键区域)
2。 Semaphore (号志)
3。 Event (事件)
4。 Mutex (Mutual Exclusive ,互斥器)
MFC 也提供了四个对应的类别:
CObject
CObject
CSyncObject
CSyncObject
CCriticalSection
CCriticalSection
CEvent
CEvent
CMutex
CMutex
CSemaphore
CSemaphore
一想到本书的厚度,我就打消介绍同步机制的念头了。你可以在许多Visual C++ 或MFC
程序设计书籍中得到这个主题的知识。
MFC 多线程程序实例
我将在此示范如何把第1章最后的一个Win32 多线程程序MltiThrd 改装为MFC 程序。
我只示范主架构(与CWinThread、AfxBeginThread 、ThreadFunc 有关的部份),程序
绘图部份留给您做练习。
766
…………………………………………………………Page 829……………………………………………………………
14 MFC
第 章 多緒程式設計
首先我利用MFC AppWizard 产生一个Mltithrd 项目,放在书附盘片的Mltithrd。14 子目
录中,并接受MFC AppWizard 的所有预设选项。
接下来我在resource。h 中加上一些定义,做为执行线程函数的参数,以便在绘图时能够把
代表各执行线程的各个长方形涂上不同的颜色:
#define HIGHEST_THREAD 0x00
#define ABOVE_AVE_THREAD 0x3F
#define NORMAL_THREAD 0x7F
#define BELOW_AVE_THREAD 0xBF
#define LOWEST_THREAD 0xFF
然后我在Mltithrd。cpp 中加上一些全域变量(你也可以把它们放在CMltithrdApp 之
中。我只是为了图个方便):
CMltithrdApp theApp;
CWinThread* _pThread'5';
DWORD _ThreadArg'5' = { HIGHEST_THREAD; // 0x00
ABOVE_AVE_THREAD; // 0x3F
NORMAL_THREAD; // 0x7F
BELOW_AVE_THREAD; // 0xBF
LOWEST_THREAD // 0xFF
}; //用来调整四方形颜色
然后在CMltithrdApp::InitInstance 函数最后面加上一些码:
// create 5 threads and suspend them
int i;
for (i= 0; i《 5; i++)
{
AfxBeginThread CMltithrdView::ThreadFunc
_pThread'i' = ( ;
&_ThreadArg'i';
THREAD_PRIORITY_NORMAL;
0;
CREATE SUSPENDED
_ ;
NULL);
}
767
…………………………………………………………Page 830……………………………………………………………
第篇 深入 MFC 程式設計
// setup relative priority of threads
_pThread'0'…》SetThreadPriority (THREAD_PRIORITY_HIGHEST);
_pThread'1'…》SetThreadPriority (THREAD_PRIORITY_ABOVE_NORMAL);
_pThread'2'…》SetThreadPriority (THREAD_PRIORITY_NORMAL);
_pThread'3'…》SetThreadPriority (THREAD_PRIORITY_BELOW_NORMAL);
_pThread'4'…》SetThreadPriority (THREAD_PRIORITY_LOWEST);
这样一来我就完成了五个worker threads 的产生,并且将其优先权做了…2~+2 范围之间
的微调。
接下来我应该设计执行线程函数。就如我在第1章已经说过,这个函数的五个执行线程可以
使用同一个执行线程函数。本例中是设计为全域函数好呢?还是static 成员函数好?如果
是后者,应该成为哪一个类别的成员函数好?
为了「要在执行线程函数做窗口绘图动作」的考量,我把执行线程函数设计为CMltithrdView
的一个static 成员函数,并遵循应有的函数类型:
// in MltithrdView。h
class CMltithrdView : public CView
{
。。。
public:
CMltithrdDoc* GetDocument();
static UINT ThreadFunc(LPVOID);
。。。
};
// in MltithrdView。cpp
UINT CMltithrdView::ThreadFunc(LPVOID ThreadArg)
{
DWORD dwArg = *(DWORD*)ThreadArg;
// 。。。在这里做如同第1章的MltitThrd 一样的绘图动作
return 0;
}
好,到此为止,编译联结,获得的程序将在执行后产生五个执行线程,并全部冻结。以Process
Viewer (Visual C++ 5。0 所附工具)观察之,证明它的确有六个执行线程(包括一个主执行
线程以及我们所产生的另五个执行线程):
768
…………………………………………………………Page 831……………………………………………………………
14 MFC
第 章 多緒程式設計
接下来,留给你的操作是:
1。 利用资源编辑器为程序加上各菜单项目,如图1…9。
2。 设计上述菜单项目的命令处理例程。
3。 在执行线程函数ThreadFunc 内加上计算与绘图能力。并判断使用者选择何种延
迟方式,做出适当反应。
769
…………………………………………………………Page 832……………………………………………………………
第篇 深入 MFC 程式設計
770
…………………………………………………………Page 833……………………………………………………………
15 AppWizard
第 章 定製個
第15 章
定制一个 AppWizard
我们的Scribble 程序一路走来,大家可还记得它一开始并不是平地而起,而是由
AppWizard 以「程序代码产生器」的身份,自动为我们做出一个我所谓的「骨干程序」来?
Developer's Studio 提供了一个开放的AppWizard 接口。现在,我们可以轻易地扩充
AppWizard :从小规模的扩充,到几乎改头换面成为一种全新类型的程序代码产生器。
Developer's Studio 提供了许多种不同的项目类型,供你选择。当你选按Visual C++ 5。0 整
合环境中的【File/New 】命令项,并选择【Projects 】附页,便得到这样的对话窗画面:
771
…………………………………………………………Page 834……………………………………………………………
第篇 深入 MFC