面試的時候,我們經常會被問到程序和線程的差別是什麼?這個問題也曾困擾過我,在之前,都是百度搜尋一下,記一下答案,就糊弄過去了,一直不曾深入的去研究,今天通過這篇部落格,以作業系統的發展作為脈絡,從作業系統的出現和發展來和大家一起學習程序和線程,并分析程序和線程間的差別。
1.舉個栗子
在正式開始本文之前,我們通過一個例子給大家簡答的說下程序和線程。QQ聊天大家應該都用過吧,在我們小時候,為了QQ等級的提升,我們一台電腦會挂好幾個賬号,此時,每登入的一個賬号,就是一個程序;那我們在聊天的過程中,打開和某個好友的聊天視窗時,這個對應的就是線程。通過這個小例子,大家也能簡單的了解程序和線程的形式,下面正式開始我們的内容。
2.程序
在學習程序前,大家思考幾個問題,程序是什麼?程序被引入的原因是什麼?
1945年第一台計算機出現的時候,那個時候還不存在作業系統,計算機的運作是需要人工的方式通過紙帶将程式和資料輸入到記憶體中,然後計算機才可以執行程式;後面為了解決人機沖突及CPU和I/O裝置之間速度不比對的沖突,出現了脫機輸入/輸出方式,通過外圍機來控制程式和資料的輸入和運算結果的輸出;為了實作對作業的連續處理,發展到單道批處理系統,他可以将一批作業以脫機方式輸入到外存中,并且配上監督程式(Monitor),來控制作業的連續執行;然後就是我們的重點了,為了進一步提高資源使用率和系統吞吐量,多道批處理系統同一時刻将多個作業調入到記憶體當中,使他們共享CPU和系統中的各種資源,在一定程度上也隻有多道批處理系統才算的上的真正的作業系統,從下圖我們可以看到,多道批處理可以在同一時段裡同時運作多個程式,在某個程式發生I/O請求或者其他等待事件事,将處理機釋放,讓其他的程式可以獲得處理機并執行,這裡引出了并發的概念。

并發:指兩個或多個事件在同一時間間隔内發生。程式的并發執行有以下的特征:
1.間斷性:程式執行過程可能會發生中斷,是并發程式具有“執行–暫停–執行”這種間斷性規律;
2.失去封閉性:程式執行過程中,為其配置設定的資源的狀态不會僅僅被該程式使用,别的并發程式也可通路;
3.不可再現性:因為失去了封閉性,也将導緻并發的執行結果失去了可再現性。
對于程式的并發執行,因為失去了封閉性,并具有間斷性,以及其運作結果的不可再現性,這些也導緻了通常的程式是不能參與并發執行的,否則程式不能按照我們的設計運作,無法得到我們的預期結果,也就失去了并發執行的意義。為了能使程式并發的執行,并且可以對并發執行的程式加以描述和控制,OS的設計人員引入了程序的概念。
講到這裡,我們對程序被引入的目的這個問題做了解答,程序被引入的目的就是為了增加作業系統的并發性,也就是可以是為了保證程式可以并發的執行,下面我們就一起來探讨一下程序是什麼?
在傳統作業系統中對于程序的定義,比較典型的定義有:
1)程序是程式的一次執行;
2)程序是一個程式及其資料在處理機上順序執行時所發生的的活動;
3)程序是具有獨立功能的程式在一個資料集合上運作的過程,它是系統進行資源配置設定和排程的一個獨立機關。
可能大家更熟悉的定義是如下:程序是程序實體(程式段、相關的資料段、程序控制塊PCB)的運作過程,是系統進行資源配置設定和排程的一個獨立機關。
不過這裡給出的定義和大家熟悉的是一樣的麼?一般部落格裡給出的程序的定義一般如下:程序是系統進行配置設定和管理資源的基本機關。這裡和我們的給出的定義是不是有些差別,首先,程序不在是系統進行排程(運作)的獨立機關了,大家想一想,這兩個定義究竟哪一個才是對的呢?
細心的讀者可能已經看到了在前面加粗的文字-----傳統作業系統,這裡可能大家就有些疑惑了,作業系統怎麼還區分傳統和非傳統呢?作業系統按照其發展,将作業系統分為傳統作業系統和現代作業系統,其主要的差別就是管理的硬體資源,傳統的作業系統一般是單核CPU,其他的配置也都較低,現代的作業系統處理器基本上都是多核的,顯示卡、記憶體也都有極大的進步。
是以說,上面的兩個定義都是對的,我在上面給出的線程的定義是在傳統作業系統中的,是程序被引入時開發人員對程序的定義,而大家熟悉的定義,是在現代作業系統中的。現在使用的較多的定義都是現代作業系統中的定義,但是如果你能了解程序的演進,對你面試或者知識的了解還是非常有幫助的。
3.線程
現在,講到線程了,大家同樣思考幾個問題,線程又是什麼?線程被引入的原因是什麼?
上面我們講到在傳統作業系統中,程序是可擁有資源的獨立機關,同時又是一個可獨立排程和分派的基本機關。那在這種情況下,我們來看,程式并發執行需要付出的時空開銷:
1.建立程序,此時需要為程序配置設定除處理機以外的所有資源,如記憶體、I/O裝置,以及建立對應的PCB;
2.撤銷程序,此時又需要将建立時配置設定的資源執行回收操作,然後撤銷PCB;
3.程序切換,對程序上下文切換時,需要保留目前程序的CPU環境,設定新被排程程式選中程序的CPU環境。
從上面我們可以看到,由于程序是一個資源的擁有者,是以在建立、撤銷和切換中,系統必須為之付出較大的時空開銷,這也就限制了作業系統中所設定的程序的數目,而程序的切換也不宜過于頻繁,進而限制了并發程度的進一步提高。
講到這裡,線程被引入的原因是不是呼之欲出了,目的就是為了減少程式在并發執行時所付出的時空開銷,使作業系統具有更好的并發性。
引出了線程的概念後,傳統的作業系統就演變成了現代作業系統。在現代作業系統中我們來看下線程的定義:作為排程和分派的基本機關。和在傳統作業系統中程序的定義相比,這裡将程序的功能給拆分了,程序作為資源配置設定的機關,而将獨立排程和分派的功能分給了線程,是以線程也被稱為輕型程序。這樣作業系統就可以分開的處理(資源和排程分派),對于擁有資源的基本機關(程序),不對之施以頻繁的切換,對于隻擁有少量必要資源的線程來實施排程和分派。
講到這裡線程部分就結束了麼,NONONO,大家在前面有沒有注意到提到的現代作業系統的重要特點是多核CPU,前面也講到,程序的建立、撤銷和切換所需付出的時空開銷限制了OS中程序的數量,并且對于程序來說,一個程序隻能運作在一個處理機上,就算程序在運作的過程中,其他的處理機處于空閑狀态,是不是對程序的執行也沒有任何的幫助?但是,有了線程之後,一切就變得不同了,雖然一個線程也隻能運作在一個處理機上,但是線程由于其體量小的特點,OS中線程的數量遠遠大于程序的數量,這樣一個程序中的多個線程就可以并發的執行在多個處理機上了,這樣才能充分地的利用技術革新帶來的便利----多核處理機,又進一步的提高了作業系統的并發性。
同時也正因為多處理機的迅速發展,OS的發展也得到了大大的促進。
4.栗子講解
下面通過對本文開始時的QQ聊天的例子的講解,來說明程序和線程執行的特點。
1.在上面的例子中,每個賬号登入後,OS會建立一個對應的程序,會為之配置設定資源,我們登入的賬号越多,建立的程序也就越多,最直覺的感受就是,我們的電腦會變得有些卡頓(在當時,電腦的性能并不高,是以比較明顯),這是因為建立程序、程序的排程時空開銷較大,也就導緻OS中的記憶體、CPU等資源的緊張。
2.另一個情況,隻登陸一個QQ,你打開了多個聊天視窗,是不是對你的電腦流暢度沒有可以感覺到的影響,這是因為線程的建立和排程所付出的時空開銷很低,沒有對OS形成較大的負擔;
3.還有一種情況,可能大家沒有注意到,就是隻登陸一個賬号,對應着OS中建立了一個程序,打開多個聊天視窗,OS中建立多個程序,這裡程序和線程的關系是不是一對多的關系,一個程序可以建立多個線程。
4.程序和線程的差別
講到這裡,我們也把程序是什麼,線程是什麼講明白了,程序和線程出現的目的,為了解決什麼問題也弄清楚了,下面我們來總結下上面我們講的内容,同時也對程序和線程之間的差別進行一個總結。
首先是兩者的定義:程序是OS配置設定資源的基本機關;線程作為OS排程和分派的基本機關;
下面我們從排程行、并發性、系統開銷和擁有資源等方面對線程和程序做一個比較。
1.排程的基本機關
這裡也主要是定義上的差別,在傳統的OS中,程序是作為獨立排程和分派的基本機關,因而程序是可以獨立運作的基本機關。但是因為每次排程時,都需要程序上下文的切換,開銷較大。而在引入了線程的OS中(現代OS),已把線程作為排程和分派的基本機關,因而線程是能獨立運作的基本機關。因為線程隻擁有較少的資源,是以線程切換的代價遠小于程序。在同一個程序中,線程的切換不會引起程序的切換,但是從一個程序中的線程切換到另一個程序中的線程,必然會引起程序的切換。
2.并發性
在引入線程的OS中,不僅程序之間可以并發執行,而且在一個程序中的多個線程之間亦可并發執行,甚至允許一個程序中的所有線程都能并發的執行。同樣,不同程序中的線程也能并發的執行,使OS具有了更好的并發性,進而能更加有效的提高系統的資源利用與和系統的吞吐量。
3.擁有資源
程序可以擁有資源,并作為系統中擁有資源的一個基本機關。然而,線程本身是不擁有系統資源的,而是僅擁有一點必不可少、能保證獨立運作的資源,包括線程控制塊TCB、程式計數器、一組寄存器和堆棧。
但是線程除了擁有自己的少量資源外,多個線程之間還可共享該程序(線程所屬的程序)所擁有的資源。
4.獨立性
同一程序中的不同線程之間的獨立性要比不同程序之間的獨立性低得多。這是因為程序擁有自己的獨立位址空間和其他資源,并且為了防止不同程序之間彼此幹擾和破壞,除了一些共享的全局變量外,不允許其他程序通路,是以不同程序之間的獨立性高;另一方面,同一程序中的不同線程往往是為了提高并發性以及進行互相之間的合作而建立的,他們之間共享程序中的位址空間和資源,是以獨立性低。
5.系統開銷
OS為建立、撤銷、排程程序耗費的資源明顯的大于線程建立、撤銷和排程所付出的開銷。舉個例子,線程的建立要比程序的建立快約30倍,線層的上下文切換要比程序的上下文切換快5倍。此外,由于一個程序中的多個線程具有相同的位址空間(共用程序的),線程之間的同步與通信也比程序的簡單。
6.支援多處理機系統
在多處理機系統中,對于傳統的程序,即單線程程序,不管有多少個處理機,該程序隻能運作在一個處理機上。但是對于多線程程序,就可以将一個程序中的多個線程配置設定到多個處理機上,使他們并發執行,這無疑會加快程序的完成。