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

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

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



                            30h  WORD      un3                                             38h   DWORD   MessageQueue 

                                                                                                                                    MSG 

                            32h  WORD      cRing0Threads                                   3Ch   DWORD   pTLSArray 

                            34h  HANDLE    HeapHandle                                      40h   PPROCESS_DATABASE   pProcess2 

                            38h  HTASK     W16TDB                                          44h   DWORD   Flags 

                                                                                           48h   DWORD   TerminationStatus          MSG 

                            3Ch  DWORD     MemMapFiles 

                                                                                           4Ch   WORD    TIBSelector 

                            40h  PENVIRONMENT_DATABASE    pEDB                             4Eh   WORD    EmulatorSelector 

                            44h  PHANDLE_TABLE    pHandleTable                             50h   DWORD   cHandles 

                                                                                                                                    MSG 

                            48h  struct _PROCESS_DATABASE*    ParentPDB                    54h   DWORD   WaitNodeList 

                            4Ch  PMODREF   MODREFlist                                      58h   DWORD   un4 

                            50h  DWORD     ThreadList                                      5Ch   DWORD   Ring0Thread 

                                                                                                                                    MSG 

                            54h  DWORD     DebuggeeCB                                      60    PTDBX   pTDBX 

                            58h  DWORD     LocalHeapFreeHead                               64h   DWORD   StackBase 

                                                                                           68h   DWORD   TerminationStack 

                            5Ch  DWORD     InitialRing0ID 

                                                                                           6Ch   DWORD   EmulatorData 

                             60h  CRITICAL_SECTION    crst 

                                                                                           70h   DWORD   GetLastErrorCode 

                            78h  DWORD     un4'3' 

                                                                                           74h   DWORD   DebuggerCB 

                            84h  DWORD     pConsole                                        78h   DWORD   DebuggerThread 

                            88h  DWORD     tlsInUseBits1                                   7Ch   PCONTEXT   ThreadContext 

                            8Ch  DWORD     tlsInUseBits2                                   80h   DWORD   Except16List 

                             90h  DWORD     ProcessDWORD                                   84h   DWORD   ThunkConnect 

                             94h  struct _PROCESS_DATABASE*   ProcessGroup                 88h   DWORD   NegStackBase 

                                                                                           8Ch   DWORD   CurrentSS 

                             98h  DWORD     pExeMODREF 

                                                                                           90h   DWORD   SSTable 

                             9Ch  DWORD     TopExcFilter 

                                                                                           94h   DWORD   ThunkSS16 

                            A0h  DWORD     BasePriority 

                                                                                           98h   DWORD   TLSArray '64' 

                            A4h  DWORD     HeapOwnList                                     198h  DWORD   DeltaPriority 

                            A8h  DWORD     HeapHandleBlockList                             19Ch  DWORD   un5'7' 

                            ACh  DWORD     pSomeHeapPtr                                    1B8h  DWORD   pCreateData16 

                            B0h  DWORD     pConsoleProvider                                1BCh  DWORD   APISuspendCount 

                            B4h  WORD      EnvironSelector                                 1C0h  DWORD   un6 

                            B6H  WORD      ErrorMode                                       1C4h  DWORD   WOWChain 

                            B8h  DWORD     pevtLoadFinished                                1C8h  WORD    wSSBig 

                                                                                           1CAh  WORD    un7 

                            BCh  WORD      UTState 

                                                                                           1CCh  DWORD   lp16SwitchRec 

                                                                                           1D0h  DWORD   un8'6' 

                                                                                           1E8h  DWORD   pSomeCritSect1 

                                                                                           1ECh  DWORD   pWin16Mutex 

                                                                                           1F0h  DWORD   pWin32Mutex 

                                                                                           1F4h  DWORD   pSomeCritSect2 

                                                                                           1F8h  DWORD   un9 

                                                                                           1FCh  DWORD   ripString 

                                                                                           200h  DWORD   LastTlsSetValueEIP'64' 



                                  图14…3 执行线程数据结构 (PDB ) 的细部内容 ( 资料整理自Windows 95 



                                            System Programming SECRETS; Matt Pietrek; IDG Books) 



750 


…………………………………………………………Page 813……………………………………………………………

                                            14     MFC  

                                          第 章       多緒程式設計 



执行线程排程(Scheduling) 



      排程器挑选「下一个获得CPU 时间的执行线程」的唯一依据就是:执行线程优先权。如果 



      所有等待被执行的执行线程中,有一个是优先权16,其它所有执行线程都是优先权15  (或 



      更低),那么优先权16 者便是下一个夺标者。如果执行线程A和B同为优先权16,排程 



      器会挑选等待比较久的那个(假设为执行线程A)。当A的时间切片(timeslice )终了,如 



      果B以外的其它执行线程的优先权仍维持在15  (以下),执行线程B就会获得执行权。 



       「如果B以外的其它执行线程的优先权仍维持在15  (以下)。。。」,唔,这听起来彷佛优先 



      权会变动似的。的确是。为了避免朱门酒肉臭、路有冻死骨的不公平情况发生,排程器 



      会弹性调整执行线程优先权,以强化系统的反应能力,并且避免任何一个执行线程一直未能 



      接受CPU  的润泽。一般的执行线程优先权是7,如果它被切换到前景,排程系统可能暂 



      时地把它调升到8 或9 或更高。对于那些有着输入消息等待被处理的执行线程,排程系 



      统也会暂时调高其优先权。 



      对于那些优先权本来就高的执行线程,也并不是有永久的保障权利。别忘了Windows 毕竟 



      是个消息驱动系统,如果某个执行线程调用::GetMessage 而其消息队列却是空的,这个执 



      行线程便被冻结,直到再有消息进来为止。冻结的意思就是不管你的优先权有多高,暂时 



      退出排班行列。执行线程也可能被以::SuspendThread 强制冻结住(::ResumeThread 可以解 



      除冻结)。 



      会被冻结,表示这个执行线程「要去抓取消息,而执行线程所附带的消息队列中却没有消息」。 



      如果一个执行线程完全和UI 无关呢?是否它就没有消息队列?倒不是,但它的程序代码中 



      没有消息循环倒是事实。是的,这种执行线程称为worker thread 。正因它不可能会被冻结, 



      所以它绝对不受Win16Mutex 或其它因素而影响其强制性多任务性质,及其优先权。 



 Thread Context 



      Context 一词,我不知道有没有什么好译名,姑且就用原文吧。它的直接意思是「前后关 



      系、脉络;环境、背景」。所以我们可以说Thread Context 是构成执行线程的「背景」。 



                                                                751 


…………………………………………………………Page 814……………………………………………………………

              第篇    深入  MFC  程式設計 



              那是指什么呢?狭义来讲是指一组缓存器值(包括指令指位器IP )。因为执行线程常常会 



              被暂停,被要求把CPU 拥有权让出来,所以它必须将暂停之前一刻的状态统统记录下 



              来,以备将来还可以恢复。 



              你可以在WINNT。H  中找到一个CONTEXT 数据结构, 它可以用来储存Thread 



              Context  。::GetThreadContext 和::SetThreadContext 可以取得和设定某个执行线程的 



              context ,因而改变该执行线程的状态。这已经是非常低阶的行为了。Matt Pietrek 在其 



              Windows 95 System Programming SECRETS  一书第10 章,写了一个Win32 API Spy 程 



               式,就充份运用了这两个函数。 



               我想我们在操作系统层面上的执行线程学理基础已经足够了,现在让我们看看比较实际一 



               点的东西。 



        从程序设计层面看执行线程 



              书籍推荐:如果要从程序设计层面来了解执行线程,Jim Beveridge 和Robert Wiener 合着 



              的Multithreading Applications in Win32  (Win32 多线程程序设计/侯俊杰译/峰出版)是 



              很值得推荐的一份知识来源。这本书介绍执行线程的学理观念、程序方法、同步控制、资 



              料一致性的保持、C runtime library 的多线程版本、C++  的多线程程序方法、MFC 中的多线程 



              程序方法、除错、进程通讯(IPC )、DLLs。。。 ,以及约50 页的实际应用。 



              书籍推荐:Jeffrey Richter  的Advanced Windows 在进程与执行线程的介绍上(第2章和第 



               3章),也有非常好的表现。他的切入方式是详细而深入地叙述相关Win32 API  的规格 



              与用法。并举实例左证。 



              如何产生执行线程?我想各位都知道了,::CreateThread 可以办到。图14…4 是与执行线程有 



              关的Win32 API 。 



752 


…………………………………………………………Page 815……………………………………………………………

                                                      14      MFC  

                                                   第 章          多緒程式設計 



与执行线程有关的Win32 API                         功能 



AttachThreadInput                   将某个执行线程的输入导向另一个执行线程 



CreateThread                   产生一个执行线程 



ExitThread                                      结束一个执行线程 



GetCurrentThread                          取得目前执行线程的handle 



GetCurrentThreadId              取得目前执行线程的ID 



GetExitCodeThread             取得某一执行线程的结束代码(可用以决定执行线程是否 



                            已结束) 



GetPriorityClass            取得某一进程的优先权等级 



GetQueueStatus              传回某一执行线程的消息队列状态 



GetThreadContext            取得某一执行线程的context 



GetThreadDesktop            取得某一执行线程的desktop 对象 



GetThreadPriority           取得某一执行线程的优先权 



GetThreadSelectorEntry      除错器专用,传回指定之执行线程的某个selector 的 



LDT                         记录项 



ResumeThread                将某个冻结的执行线程恢复执行 



SetPriorityClass            设定优先权等级 



SetThreadPriority           设定执行线程的优先权 



Sleep                       将某个执行线程暂时冻结。其它执行线程将获得执行权。 



SuspendThread               冻结某个执行线程 



TerminateThread             结束某个执行线程 



TlsAlloc                    配置一个TLS     (Thread Local Storage ) 



TlsFree                     释放一个TLS     (Thread Local Storage ) 



TlsGetValue                 取得某个TLS     (Thread Local Storage )的内容 



TlsSetValue                 设定某个TLS     (Thread Local Storage )的内容 



WaitForInputIdle            等待,直到不再有输入消息进入某个执行线程中 



图14…4 与执行线程有关的Win32 API 函数 



                                                                                  753 


…………………………………………………………Page 816……………………………………………………………

             第篇    深入  MFC  程式設計 



             注意,多执行线程并不能让程序执行得比较快(除非是在多CPU 机器上,并且使用支持 



             symmetric multiprocessing  的操作系统),只是能够让程序比较「有反应」。试想某个程 



             式在某个菜单项目被按下后要做一个小时的运算工作,如果这份工作在主执行线程中做, 



             而且没有利用PeekMessage  的技巧时时观看消息队列的内容并处理之,那么这一个小时 



              内这个程序的使用者接口可以说是被冻结住了,将毫无反应。但如果沉重的运算工作是 



              由另一个执行线程来负责,使用者接口将依然灵活,不受影响。 



         Worker Threads 和 U  I Threads 



             从Windows 操作系统的角度来看,执行线程就是执行线程,并未再有什么分类。但从MFC 



              的角度看,则把执行线程划分为和使用者接口无关的worker threads ,以及和使用者接口 



              (UI )有关的UI threads 。 



             基本上,当我们以::CreateThread 产生一个执行线程,并指定一个执行线程函数,它就是一 



             个worker thread ,除非在它的生命中接触到了输入消息…这时候它应该有一个消息回 



             路,以抓取消息,于是该执行线程摇身一变而为UI thread 。 



             注意,执行线程本来就带有消息队列,请看图14…3 的TDB 结构。而如果执行线程程序代码 



              中带有一个消息循环,就称为UI thread 。 



          错误观念 



             我记得曾经在微软的技术文件中,也曾经在微软的范例程序中,看到他们鼓励这样的作 



             法:为程序中的每一个窗口产生一个执行线程,负责窗口行为。这种错误的示范尤其存在 



             于MDI 程序中。是的,早期我也沾沾自喜地为MDI 程序的每一个子窗口设计一个执 



             行线程。基本上这是错误的行为,要付出昂贵的代价。因为子窗口一切换,上述作法会导 



             至执行线程也切换,而这却要花费大量的系统资源。比较好的作法是把所有UI               (User 



             Interface )动作都集中在主执行线程中,其它的「纯种运算工作」才考虑交给worker threads 



             去做。 



754 


…………………………………………………………Page 817……………………………………………………………

                                            14     MFC  

                                          第 章       多緒程式設計 



正确态度 



     什么是使用多执行线程的好时机呢?如果你的程序有许多事要忙,但是你还要随时保持注 



     意某些外部事件(可能来自硬件或来自使用者),这时就适合使用多执行线程来帮忙。 



     以通讯程序为例。你可以让主执行线程负责使用者接口,并保持中枢的地位。而以一个分 



     离的执行线程处理通讯端口, 



MFC 多线程程序设计 



     我已经在第1章以一个小节介绍了Win32 多线程程序的写法,并给了一个小范例 



     MltiThrd 。这一节,我要介绍MFC 多线程程序的写法。 



探索CWinThread 



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