友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

深入浅出MFC第2版(PDF格式)-第139部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!




     是我必须警告你,多线程程序的设计成功关键并不在此。如果你的每一个执行线程都非常独 



     立,彼此没有干联,也就罢了。但如果许多个执行线程互有关联呢?有经验的人说多线程程 



     式设计有多复杂多困难,他们说的并不是执行线程本身,而是指执行线程与执行线程之间的同 



     步控制。 



     原因在于,没有人能够预期执行线程的被执行。在一个合作型多任务系统中(例如Windows 



     3。x),操作系统必须得到程序的允许才能够改变执行线程。但是在强制性多任务系统中(如 



     Win95 或WinNT ),控制权被排程器强制移转,也因此两个执行线程之间的执行次序变得 



     不可预期。这不可预期性造成了所谓的race conditions 。 



     假设你正在一个文件服务器中编辑一串电话号码。文件打开来内容如下: 



        Charley 572…7993 



        Graffie 573…3976 



        Dennis 571…4219 



                                                                  763 


…………………………………………………………Page 826……………………………………………………………

               第篇    深入  MFC  程式設計 



               现在你打算为Sue 加上一笔新资料。正当你输入Sue  电话号码的时候,另一个人也打 



               开文件并输入另一笔有关于Jason  的资料。最后你们两人也都做了存盘动作。谁的资料 



               会留下来?答案是比较晚存盘的那个人,而前一个人的输入会被覆盖掉。这两个人面临 



               的就是race condition 。 



               再举一个例子。你的程序产生两个执行线程,A和B。执行线程B的任务是设定全域变量X。 



               执行线程A则要去读取X。假设执行线程B先完成其工作,设定了X,然后执行线程A才执行, 



               读取X,这是一种好的情况,如图14…6a。但如果执行线程A先执行起来并读取全域变量 



               X,它会读到一个不适当的值,因为执行线程B还没有完成其工作并设定适当的X。如图 



               14…6b。这也是race condition 。 



               另一种执行线程所造成的可能问题是:死结(deadlock )。图14…7 可以说明这种情况。 



                         图14…6a race condition (good) 



                 执行线程A                                执行线程B  



                                   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 


……………
返回目录 上一页 下一页 回到顶部 0 0
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!