四刷 3600 冊  

《Win32 多緒程式設計》
Multithreaded Applications in Win32

侯捷 譯

jim.jpg (16257 bytes)

繁體版 勘誤


【基本資料】

書名:Win32 多緒程式設計
出版:眳p,1997.08
ISBN:957-566-075-7
頁數: 16 章,453 頁
定價:NT$ 640.0

原著:Multithreaded Applications in Win32
原著作者:Jim Beveridge & Robert Wiener
原著出版:Addison Wesley, 1997
原著ISBN:0-201-44234-5
原著定價:US$ 39.95

【譯序】

敘緒之序 絮絮如絮

(譯 序)

作者在本書第一章的第一句話讓我沉思良久。他說:『電腦工業界每有新的技術問世,人們總是不遺餘力地去擔憂「它是不是夠重要」。公司行號虎視眈眈地注意其競爭對手,直到對方採用並宣揚這技術有多麼重要,才開始急急趕上。不論這技術是不是真的很重要,每一個人都想盡辦法讓終端用戶感覺「真的很重要」。終端用戶終於真的覺得需要它了 -- 即使他們完全不瞭解那是什麼東東。』

執行緒(thread)大約就是其一吧。OS/2 和 Windows NT 以及 Windows 95 上市時,一再強調其強制性多工(preemptive multitasking)的多執行緒(multithreaded)環境。霎時間線頭到處飛舞,電腦科學裡十分高深的名詞也在街巷里弄之間傳播了開來,頗有點 "Nerual Fuzzy" 洗衣機的味道。

這倒也算好事。沒有把「執行緒」搞清楚是怎麼回事,對終端用戶而言或許還沒有關係,但是對搞技術的人可就不妙。執行緒絕對可以提昇程式的執行效率?所以儘量多產生執行緒來幫助程式工作?任何種類的程式都可以獲得多執行緒的好處?錯!錯!錯!這種似是而非的觀念可能把你的程式帶往一種更壞(而不是更好)的境界。 

執行緒並不是新東西,只是它藉著 Windows 的龐大裝機量,第一次廣泛進入個人電腦的世界,帶給我們巨大的刺激。執行緒並不難產生,要它們分工可以,但要它們合作就得相當花心思了。執行緒不一定帶來好處,運用不好它會在執行效率上懲罰你。

執行緒是 Win32 作業系統和 Win32 程式設計上不可或缺的重要環節,每一本重量級的書籍都不會忽略這個題目(請參考附錄B)。但是這些書多半僅以一章(有的甚至是一節)來介紹這個題目。不夠,真的不夠。我們缺乏一本兼具理論並重實際的多緒程式設計書籍。這本書很早就在 Addison Welsey 的書目上引起我的注意。它的內容,的確兼具理論並重實際。它的輕薄短小,也在大部頭書當道的今天,讓做為讀者的我心情輕鬆不少。不過,執行緒這個主題是不可能讓我們輕鬆的,同步控制、執行緒通訊、資料一致性...,讀這本書還是請你安裝一下自己的精神。

對於這本翻譯書,我有以下幾點說明:

1. 譯本中的範例程式碼直接取自書附碟片中的實例。如果與原書內容稍有出入,那是因為作者最後又做的一點點小變動。我想,以碟片內容為主會比較實際。通常在差異之處我會以譯註的方式告訴你。

2. 這本譯作保留了相當多的原文技術名詞。這是一種嘗試,主要是考慮到這本書的潛在讀者。如果不講原文名詞,可能他們反而要倒譯回去,那麼本書就適得其反了。許多地方我不厭其煩地在中文名詞後面加上原文名詞,為的也是同樣的原因。

「執行緒」這項技術非常重要,當支援多處理器(CPU)的作業系統逐漸普及,當多處理器的 PC 也逐漸普及,我相信「執行緒」是每一位技術人員都必須擁有的技術。即使是現在,「執行緒」能夠提高程式的反應度,也是高級技術人員應該追求的技術。

侯俊傑 1997.01.30 于新竹

 

【導讀】

前言

1992 年,我參加了第二屆的 Microsoft Professional Developers Conference,當時 Win32 首次對大量觀眾展示。這是一個重大的事件,其中有許多蠱魅的新技術第一次亮相。觀眾不斷地對展示的東西喝采。當我看到這些新技術,我身上 Unix 的那一部份說『時候到了』,而 Windows 3.1 的那一部份則是高呼『哈利路亞』。

五年過去了,好幾版 Windows NT 問世了。我愈是深入此書,愈是瞭解1992 年的那場盛宴之中我的瞭解多麼貧乏。我聽過許多「睿智」的話,像是「為 MDI 程式的每一個視窗準備一個執行緒」之類,事實上根本錯誤。有些技術(諸如 overlapped I/O)很明顯地被曲解。

當我鑽研此書,我發現許多其他書籍和文章從頭到尾描述了各式各樣的 Win32 函式,卻很少著墨在如何使用它們,或如何搭配其他函式使用。某些函式,例如 MsgWaitForMultipleObjects(),是 Win32 程式的運轉中心,卻幾乎沒有任何範例程式正確使用過它。在我所發現的文件給了我太多的挫敗之後,我決定儘可能以實務導向的方式完成此書,如此一來你就能看到那些 Win32 函式一起合作的情景。

這本書的讀者群很廣,Win16 Unix 上的程式開發者欲移轉到 Win32,或是有經驗的 Win32 程式開發者,都是我的對象。你會發現一些不曾看過的問答,像是「為什麼 _beginthreadex() 真的很重要」等等。程式範例從基本層面到同步機制,到多緒 COM ISAPI 應用程式,都有。

這是一本可以讓你上手實驗「Win32 執行緒」的書。我描述了基礎觀念,如果你需要更理論性的知識,你得多看點其他資料。執行緒的大部份問題都已經被像 Dijkstra Courtois 那樣的人在 25 年前就解決掉了。他們的論文直到今天還適用。

如果你對那些只挑軟柿子吃而故意忽略困難部份的書籍感到絕望,我希望本書能夠讓你絕地逢生。某些章節是經過了長時間的實驗、多篇相關文章(來自雜誌、期刊、Microsoft Knowledge Base)的閱讀、眾多原始碼的剖析之後,萃鍊而得。像「執行緒與 C runtime 函式庫以及 MFC 的關係」這種主題,我保證你會從中獲得許多閃亮寶石。

許多程式員對於執行緒是既期待又怕受傷害。Unix 的人嘲笑它,因為行程(process)看起來就已經不錯了。Win16 的人也嘲笑它,因為 PeekMessage() 也運作得很好嘛!我寫這本書時首要認識的一個關鍵問題就是:如果有任何一個人在乎所謂的執行緒,他為的是什麼?

如果你開發的是伺服器(server)產品,你就應該對執行緒深深在乎,因為 I/O completion ports 使用它。I/O completion ports 是唯一能夠搭配 Win32 sockets named pipes 完成高效率 I/O 的方法。請你「跑」到第6章看個明白(用走的太慢了)。

如果你開發的是 Web 產品,IISInternet Information Server)的擴充軟體也是靠多執行緒 DLLs 完成。這種技術的背景觀念散佈於整本書,而第16章告訴你如何施行那些觀念。

本書第一篇的程式是以 C 完成,C++ 的份量很少。從第二篇開始我們就往 C++ 移動了。一如我在第9章所說,C++ 是大勢所趨,不論你是否使用 MFC。如果你的 C++ 根基不穩,我希望你特別注意一下第9章。

誰應該讀這本書

凡是 C/C++ 程式開發人員,並有 Windows 程式設計經驗(不論是 Win16 Win32),企圖對執行緒、核心物件、overlapped I/O in Win32 獲得更堅實之認識者,本書就是針對你們而寫的。本書談的是 API 函式的使用、你會遭遇的問題、以及 Windows 架構對其用途的影響。

讀過本書之後,你將有能力分析哪裡是執行緒可以發揮效用的地方,哪裡是你應該閃躲它們的地方。幾乎整本書的重點都放在產生真正可用的程式。神秘手法以及不安全的設計已經被我排除了。

Unix 程式員將會發現,Win32 Unix 之間有著基礎觀念上的差異。

本書架構

本書的第一篇,「上路吧,執行緒」,為你建立必要的基礎,包括執行緒的啟動和結束、核心物件、激發和未激發狀態的意義、同步機制及其用途。有經驗的 Win32 程式員或許可以跳過這一部份。不過第6章所討論的主題(諸如 I/O completion ports),是非常重要的題目,而且總的來說,其文件非常貧乏。

本書的第二篇,「多緒程式設計的工具與策略」,介紹 C runtime 函式庫和 MFC 對執行緒的支援、如何在 USER GDI 的限制之下施行多執行緒、如何產生一個 DLL、如何對多緒程式除錯。這一部份的許多資訊來自於我們的研究和實作經驗。

本書的第三篇,「真實世界中的多緒應用程式」,談論如何組織一個程式,使它有效支援多執行緒。本篇示範兩個真實世界中的應用軟體,第一個是個 freethreaded OLE automation server,第二個是 ISAPI 程式,是個 IISInternet Information Server)擴充軟體,示範如何和 JET 資料庫交談。

關於範例程式

整本書中我用了許多文字模式程式來示範觀念。有些人不喜歡這種選擇,但我相信一個 50~100 行的程式絕對比一個有著訊息迴路、資源檔案、視窗函式...並且超過 750 行的 Windows 程式更能夠集中讀者的目光。讀這本書不會看到太多與使用者介面相關的東西。我相信本書的範例程式以其目前的形態對你會比較有幫助。

面對這些範例程式,我使用多方的錯誤檢驗。雖然這些檢驗導至程式碼看起來有些雜亂,但是錯誤檢驗對於生產一個真正的應用軟體很重要,對於一本書也很重要。

相關閱讀

有兩樣東西是任何時候你嘗試寫任何 Win32 程式時應該要準備的。第一樣東西是 Microsoft Developer Network。其光碟片內含不可置信的巨量技術資料,包括 Microsoft Knowledge Base、編譯器和 Win32 的完整手冊、以及 Microsoft Systems Journal

第二樣東西是 Jeffrey Richter 的一本卓越書籍:Advanced Windows NT : The Developers Guide to the Win32 API for Windows NT 3.5 and Windows NTMicrosoft Press1995)。雖然其中遺漏了某些 NT 3.51 的新東西,但其他方面非常有價值。

譯註:Jeffrey 的書已出至第3版,名為 Advanced Windows Third Edition. 它的小標題寫著:for Windows 95 & Windows NT 4.0

 

【目錄】

常見問答集(Frequently Asked Questions)
前言

第一篇 上路吧,執行緒

第1章 為什麼要「千頭萬緒」
一條曲折的路
與執行緒共枕
為什麼終端用戶也需要多緒多工
Win32 基礎
Context Switching
Race Conditions(競速狀態)
Atomic Operations(不可分割的動作)
執行緒之間如何通訊
好消息與壞消息

第2章 執行緒的第一次接觸
產生一個執行緒
使用多個執行緒的結果
核心物件(Kernel Objects)
執行緒結束碼(Exit Code)
結束一個執行緒
錯誤處理
背景列印(Background Printing)
成功的秘訣

第3章 快跑與等待
    看似閒暇卻忙碌(Busy Waiting)

效能監視器(Performance Monitor)
等待一個執行緒的結束
叮咚:被激發的物件(Signaled Objects)
等待多個物件
在一個 GUI 程式中等待
提要

第4章 同步控制(Synchronization)
Critical Sections(關鍵區域、臨界區域)
死結(Deadlock)
哲學家吃飯問題(The Dining Philosophers)
互斥器(Mutexes)
號誌(Semaphores)
事件(Event Objects)
從 Worker 執行緒中顯示輸出
Interlocked Variables
提要:關於同步機制(Synchronization Mechanisms)

第5章 不要讓執行緒成為脫韁野馬
乾淨地中止一個執行緒
執行緒優先權(Thread Priority)
初始化一個執行緒
提要

第6章 Overlapped I/O,在你身後變戲法
Win32 檔案操作函式
被激發的 File Handles
被激發的 Event Objects
非同步程序呼叫(Asynchronous Procedure Calls,APCs)
對檔案做 Overlapped I/O 的缺點
I/O Completion Ports
對 Sockets 使用 Overlapped I/O
提要

第二篇 多緒程式設計的工具與手法

第7章 資料一致性(Data Consistency)
認識 volatile 關鍵字
Referential Integrity
The Readers/Writers Lock
我需要鎖定嗎?
Lock Granularity
提要

第8章 使用 C Run-time Library
什麼是 C Runtime Library 多緒版本
選擇一個多緒版本的 C Runtime Library
以 C Runtime Library 啟動執行緒
哪一個好:CreateThread() 抑或 _beginthreadex()?
避免 stdio.h
一個安全的多緒程式
結束行程(Process)
為什麼你應該避免 _beginthread()
提要

第9章 使用 C++
處理有問題的 _beginthreadex() 函式原型
以一個物件啟動一個執行緒
建立比較安全的 Critical Sections
建立比較安全的 Locks
建立可交替授受(Interchangeable)的 locks
異常情況(Exceptions)的處理
提要

第10章 MFC 中的執行緒
在 MFC 中啟動一個 Worder 執行緒
安全地使用 AfxBeginThread() 的傳回值
在 MFC 中啟動一個 UI 執行緒(User Interface Thread)
和 MFC 物件共處
MFC 的同步控制
MFC 對於 MsgWaitForMultipleObjects() 的支援
提要

第11章 GDI 與視窗管理
執行緒的訊息佇列
訊息如何周遊列國
GUI 效率問題
以 Worker 執行緒完成多緒版 MDI 程式
多個上層視窗(Top Level Windows)如何是好?
執行緒之間的通訊
NT 的影子執行緒(shadow thread)
關於 "Cancel" 對話盒
鎖住 GDI 物件
提要

第12章 除錯
使用 Windows NT
有計劃地對付錯誤
Bench Testing
執行緒對話窗
運轉記錄(Logging)
Memory Trails
硬體除錯暫存器
科學方法
提要

第13章 行程之間的通訊(Interprocess Communication)
以訊息佇列權充資料轉運中心
使用共享記憶體(Shared Memory)
使用指標指向共享記憶體(Shared Memory)
較高層次的行程通訊(IPC)
提要

第14章 建造 DLLs
DLL 的通告訊息(Notifications)
通告訊息(Notifications)的問題
DLL 進入點的依序執行(Serialization)特性
MFC 中的 DLL 通告訊息(Notifications)
餵食給 Worker 執行緒
執行緒區域儲存空間(Thread Local Storage,TLS)
_declspec(thread)
資料的一致性
提要

第三篇 真實世界中的多緒應用程式

第15章 計劃一個應用程式
多執行緒的理由
要執行緒還是要行程?
多緒程式的架構
評估既有程式碼的適用性
對 ODBC 做計劃
他人開發的函式庫(Third-Party Libraries)
提要

第16章 ISAPI
Web 伺服器及其工作原理
ISAPI
IS2ODBC 範例程式
提要

第17章 OLE,ActiveX,COM
COM 的執行緒模型(COM Threading Models)
AUTOINCR 範例程式
提要

附錄A MTVERIFY 巨集
附錄B 更多的資訊