第一章 為什么要“千頭萬緒”
資源網絡收集 感謝原創者
轉自http://blog.sina.com.cn/s/blog_5678943c0100d4po.html
本章回答了如下幾個問題:
◆ 什么是多任務操作系統?多任務操作系統有哪些類型?它們有何區別?
◆ 為什么要使用多線程呢?為什么不使用多進程?線程、進程,它們到底是什么樣的東東?
◆ 多線程是如何實現的?線程是如何切換的?效率怎樣?
◆ 多線程設計是如此的誘人,難道什么代價也不用付出?怎樣才能很好地進行多線程設計呢?
合作型[cooperative]多任務和搶先式[preemptive]多任務有何不同?
兩者的最大區別是誰來把握CPU的分享。前者由程序員的“舉止良好”才可做到,后者則由操作系統決定,可以強迫應用程序把CPU分享給別人。
Microsoft Windows的前三個版本(1、2、3)屬于合作型多任務操作系統,Windows4.0(即Windows)95后均屬于強先式多任務操作系統。
記住:一個永遠有反映的UI(User Interface)是很重要的。
線程和進程有何不同?
從Win32的角度看,進程擁有內存和資源。資源則包括核心對象(如文件句柄和線程)、用戶資源(如對話框和字符串)、GDI資源(如Device Context和brushes)。
進程本身并不能夠執行,它只是提供一個安置內存和線程的地方。(進程就是一大堆對象的擁有權的集合。也就是說,進程可以擁有內存上下文、文件句柄、線程及一大串DLL模塊(被載入到這一進程地址空間中)。
進程和內存并沒有真正“做”什么事情。一旦CPU開始執行代碼,你就擁有了一個“線程”。在同一時間同一進程,你可以擁有一大把線程,執行同一段代碼。
為什么不使用多個進程?
較之進程,線程輕便、價廉,啟動速度快,退出比較快,對系統資源的沖擊比較小。
如果使用多進程,最困難的問題是如何把窗口句柄交給另一個進程。在Win32中,句柄只在其誕生地(進程中)才有意義。這是一種安全警戒,避免某個進程有意無意地危及到另一個進程的資源。
為了分享窗口句柄,你必須明明白白地產生該句柄的一個副本,并且可以被其他進程使用。在一個多線程程序中,所有線程都可以使用這個窗口的句柄,因為句柄和線程生活在同一個進程中。
如果兩個線程分屬不同的進程,那它們通常沒有辦法共享任何內存。不同進程間如果要通訊,唯有依賴特別的設計,使之擁有共享內存(shared memory)。
如果兩線程屬于同一進程,它們將共享所有的內存(包括全局變量、靜態變量)。
Context Switching及Context Switch效率
要切換不同的線程,操作系統應先切換該線程所隸屬之進程的內存,然后恢復該線程存放在CONTEXT結構中的寄存器值。此過程稱為context switch。
注:CONTEXT結構中保存了該線程上次被打斷時線程當時的狀態,也就是CPU內所有寄存器的內容。
當然,天下沒有免費的午餐,線程切換時都要繳點效率稅金。
對于單CPU而言,搶先式多任務使電腦看起來可以同時處理多個任務。但微觀上看,任一時刻,CPU只能做一件事。
多CPU的好處是,CPU越多,就有越多線程可以同時執行,不需要context switch,從而提高了系統效率。
競爭條件(Race Conditions)和原子操作(Atomic Operations)
注意在多任務操作系統中,一條C指令一定可以安全執行完畢,而不在乎context switch是否發生。
好消息與壞消息
使用線程并非沒有代價。采用多線程設計往往會加大程序設計的復雜性,必須做到小心精心安排,才能實現預期目標。
成功的秘訣是小心地規劃:誰要什么?何時要?怎么要?