進(jìn)程與線(xiàn)程雜談(一)
本站原創(chuàng ):Null
我了解不多,只能說(shuō)說(shuō)80x86上的Windows環(huán)境,其他如Alpha,Mac或者Linux,
我就一竅不通了,見(jiàn)笑見(jiàn)笑……
現代操作系統都是多任務(wù)的操作系統,在這里要澄清一個(gè)概念,Windows 3.x時(shí)代也
有所謂的多任務(wù),但是,那并不是現代意義的多任務(wù)--"搶占式多任務(wù)"。Windows 3.x的
多任務(wù)是非搶占式的,即,一個(gè)應用程序,甚至系統,要等現在正在運行的程序主動(dòng)放棄
CPU(程序員把這個(gè)禮貌的行為寫(xiě)到程序中),才能獲得執行時(shí)間片??梢钥闯?,在這種環(huán)
境中,操作系統的主動(dòng)性是很小的,只要某個(gè)已經(jīng)獲得CPU的程序不主動(dòng)放棄CPU,操作
系統就得不到時(shí)間運行,亦無(wú)法實(shí)行其管理調度功能。如果一個(gè)應用程序因崩潰而掛起,
將導致整個(gè)系統掛起。
而搶占式的多任務(wù)是指,將CPU時(shí)間片分配最需要它的應用程序,即便一個(gè)應用程序永
遠不打算放棄CPU,操作系統也能保證隨時(shí)"搶占"CPU時(shí)間,然后對當前所有的任務(wù)進(jìn)行
合理的調度。
要實(shí)現多任務(wù),首先要有CPU的支持,80x86 (Alpha?我不懂,別問(wèn)我……) 支持
多任務(wù),通過(guò)一個(gè)TSS--任務(wù)描述符,80x86能夠描述一個(gè)任務(wù)。詳細我就不說(shuō)了,和本
文關(guān)系不大,只要說(shuō)明搶占式多任務(wù)不是操作系統在單干就行了。
作為操作系統,要能夠利用CPU提供的功能才能實(shí)現多任務(wù),Windows做到了這點(diǎn)(當
然,Linux也做到了,只是我不懂……)。系統有一個(gè)核心調度程序,負責為每一個(gè)任務(wù)分配
CPU時(shí)間,允許其執行指定的一段時(shí)間,當這段時(shí)間用完后,控制權會(huì )重新交回到操作系統,
操作系統可在此時(shí)重新分配CPU時(shí)間。至于CPU時(shí)間是如何分配的,就又不是本文的范圍了。
Microsoft給出的文檔是說(shuō)"系統保證CPU時(shí)間的分配是公平的",僅此而已……。
在Windows中,一個(gè)任務(wù)就是一個(gè)線(xiàn)程,以前曾經(jīng)說(shuō)過(guò),線(xiàn)程不能沒(méi)有存儲而存在,
而其所依賴(lài)存在的存儲對象就是進(jìn)程。而一個(gè)進(jìn)程--以前也說(shuō)過(guò)了--對應一個(gè)映象(可執行
文件)。也就是說(shuō),在一個(gè)可執行文件運行時(shí),可以有多個(gè)線(xiàn)程。
好了,基本的概念大概說(shuō)明了,來(lái)討論一下它們的用途。要這些多出來(lái)(除了原始線(xiàn)程
外)的線(xiàn)程有什么用?MSDN給出的答案是"等"。但我個(gè)人認為稍微籠統了一點(diǎn)(偏激一點(diǎn)?
)。不過(guò),至少,有一點(diǎn)是肯定的--絕不要使多個(gè)線(xiàn)程同時(shí)進(jìn)行繁重的操作--除非你是建立
了CPU數目個(gè)線(xiàn)程(32路對等處理器系統?)。無(wú)論如何,實(shí)際工作的還是CPU,在這種情
況下,CPU不僅不會(huì )少執行指令,還要執行很多的排班程序指令以及任務(wù)的切換指令--反而
降低效率。
在需要等待的地方,多線(xiàn)程確實(shí)能夠發(fā)揮很高的效能。(注意,并不一定是最高,以后
將說(shuō)到經(jīng)常是更好的實(shí)現方法,這里只是說(shuō)明線(xiàn)程的用法)舉一個(gè)例子:一個(gè)網(wǎng)絡(luò )程序向遠
程主機發(fā)送了一個(gè)請求,正在等待回應,而在此期間,它還希望能夠與用戶(hù)進(jìn)行交互。一種
實(shí)現方法是:程序繼續與用戶(hù)交互,在交互的間歇檢查一下回應是否到達。而更好的方法是
建立一個(gè)新的線(xiàn)程(稱(chēng)為工作線(xiàn)程)來(lái)等待回應,原始線(xiàn)程繼續照常與用戶(hù)交互。如果您已
經(jīng)感覺(jué)到后一種方法確實(shí)比前一種方法好很多,那么,您可以不讀下一段,不用聽(tīng)我羅嗦了。
后一種方法比前一種方法好在后者執行的指令更少,因而效率更高。如果您對Windows
編程熟悉:在實(shí)現前者時(shí),必須保證能夠及時(shí)檢測到回應到達,因而就不能使用GetMessage()
而要使用PeekMessage()。如果使用GetMessage(),而恰巧在很長(cháng)的一段時(shí)間內都沒(méi)
有消息到達,原始線(xiàn)程就不會(huì )從GetMessage()返回,也就不能檢測回應是否到達。使用
PeekMessage(),可以令其在沒(méi)有消息時(shí)也立即返回,因而可以檢測回應是否到達。網(wǎng)絡(luò )
部分的情況也一樣--程序不能等回應一直等下去否則就無(wú)法與用戶(hù)交互。無(wú)論如何,在即沒(méi)
有消息、也沒(méi)有回應到達的情況下,原始線(xiàn)程沒(méi)有有效的進(jìn)入等待狀態(tài),而是不停地"空轉",
檢測二者中是否有到達的,這對系統資源顯然是極大的浪費。而對于后者,原始線(xiàn)程通過(guò)
GetMessage()有效的進(jìn)入了等待,工作線(xiàn)程也可以通過(guò)類(lèi)似的方法進(jìn)入等待,例如使用
Socket的select()。
但是,新的問(wèn)題又出現了,工作線(xiàn)程發(fā)現回應已經(jīng)到達了,它可能要通知原始線(xiàn)程才行
--它與原始線(xiàn)程是并發(fā)執行的。這就涉及到線(xiàn)程簡(jiǎn)通信了,有一種最簡(jiǎn)單的方法:Windows
消息。工作線(xiàn)程通過(guò)向原始線(xiàn)程的窗口發(fā)送一個(gè)消息,然后終止;當原始線(xiàn)程的消息循環(huán)發(fā)
現這個(gè)消息時(shí),就知道回應已經(jīng)到達了。線(xiàn)程間通信的方法還有很多,將在以后專(zhuān)門(mén)介紹。
最后要說(shuō)明的是--很重要的一點(diǎn):多線(xiàn)程經(jīng)常不是程序員主動(dòng)來(lái)使用的,而是在依賴(lài)操
作系統時(shí),已然是多線(xiàn)程了。即使用,也很有節制,濫用線(xiàn)程將適得其反。究竟什么地方應
該使用多線(xiàn)程,并沒(méi)有什么規則,將多線(xiàn)程用在該用的地方而已,當然不會(huì )刻意的使用它。
當綜合各種條件和各種可能的方案后,如發(fā)現多線(xiàn)程是最好的,就是使用多線(xiàn)程的最佳時(shí)機。
我是否說(shuō)的是廢話(huà)?呵呵,其實(shí)就像這篇文章一樣,我也很頭疼,線(xiàn)程是在遇到實(shí)際需要時(shí)
才想起用的,硬要設計一種情況來(lái)使用實(shí)在不易。有備無(wú)患。多線(xiàn)程不是殺手锏,但是掌握
它是向較高級編程邁進(jìn)的必經(jīng)之路。
聯(lián)系客服