做者:Allen B. Downeyhtml
原文:Chapter 2 Processesgit
譯者:飛龍程序員
協議:CC BY-NC-SA 4.0github
在咱們談論進程以前,我打算先定義幾個東西:shell
抽象(Abstraction):抽象是復瑣事物的簡單表示。例如,若是你開車的話,應該知道車輪向左轉的時候車也會向左行駛,反之亦然。固然,方向盤由一系列機械和傳動系統所鏈接,用於使輪子轉向,而且輪子和路面的相互做用方式也很複雜。可是做爲一個司機,你一般不須要考慮這些細節。你能夠僅僅創建方向盤的心智模型,這種心智模型就是一個抽象。編程
軟件工程的很大一部分就是設計相似這樣的抽象,容許用戶和其它程序員使用強大而複雜的系統,而沒必要知道其實現的細節。
虛擬化(Virtualization):一類很是重要的抽象就是虛擬化,它是建立可取的幻像的過程。例如,許多公共圖書館都參與了館際合做,容許它們互相借閱圖書。當我須要一本書時,有時它在個人本地圖書館的架子上,但更多狀況下它會被運到其它的館藏中。不管是哪種,我都會收到它可借閱的提醒。我並不須要知道它來自哪裏,我也不須要知道個人圖書館擁有哪一本書。通常來講,這個系統建立了一個幻象,好像個人圖書館擁有全世界的每一本書。瀏覽器
在物理上,個人圖書館的館藏可能很小,可是虛擬上我能得到的館藏包含了館際合做的每一本書。 另一個例子,大多數電腦都只鏈接到一個網絡中,而這個網絡又連接到其它網絡,等等。咱們所談論的「互聯網」,是一系列網絡和協議的合集,它將數據包從一個網絡傳送到另外一個網絡。從用戶和程序員的角度來看,整個系統的行爲就像是互聯網的每臺計算機都互相鏈接。物理鏈接的數量十分少,可是虛擬鏈接的數量十分龐大。
「虛擬」這個詞一般用於虛擬機的語境中,它是一種軟件,能夠建立運行特定系統的專用計算機的幻象。實際上,虛擬機可能和其它虛擬機一塊兒運行在不一樣的操做系統上。安全
在虛擬化的語境中,咱們一般把真實發生的事情叫作「物理的」,而把虛擬上發生的事情叫作「邏輯的」或者「抽象的」。bash
工程最重要的原則之一就是隔離(Isolation):當你設計一個帶有多個組件的系統時,將它彼此隔離是個很好的方法,這樣某個組件中的改變就不會對其它組件形成不良影響。網絡
操做系統最重要的目標之一,就是將每一個進程和其它進程隔離,使程序員沒必要考慮每一個可能的交互狀況。提供這種隔離的軟件對象叫作進程(Process)。
進程是表示運行中程序的軟件對象。我按照面向對象編程把它稱之爲「軟件對象」。工程一個對象包含數據,而且提供用於操做數據的方法。進程正是包含如下數據的對象:
程序文本,一般是機器語言的指令序列。
程序相關的數據,包括靜態數據(編譯時分配)和動態數據,後者包括運行時的棧和堆。
任何等待中的IO狀態。例如,若是進程正在等待從磁盤中讀取的數據,或者從網絡到達的數據包,這些操做的狀態也是進程的一部分。
程序的硬件狀態,這包括儲存在寄存器中的數據,狀態信息,以及程序計數器,它表示當前執行了哪一個指令。
一般一個進程運行一個程序,可是對於進程來講,加載並運行新的程序也是可能的。
也能夠在多於一個進程中運行相同的程序,這很是常見。這種狀況下,各個進程共享程序文本,可是擁有不一樣的數據和硬件狀態。
大多數操做系統提供了隔離進程的基本功能:
多任務:大多數操做系統有能力在幾乎任什麼時候候中斷一個進程,保存它的硬件狀態,而且在之後恢復它。一般,程序員不須要考慮這些中斷。程序的行爲就像在一個專用的處理器上持續運行,除了兩條指令之間的時間是不可預測的。
虛擬內存:大多數操做系統會建立幻象,每一個進程看似擁有獨立內存片而且孤立於其餘進程。一樣,程序員一般也不須要考慮虛擬內存如何工做,他們能夠當作每一個程序都擁有專用的內存片來處理。
設備抽象:運行於同一臺計算機的進程共享磁盤、網絡接口、顯卡和其它硬件。若是進程直接和這些硬件交互而不加協調,就必定會產生混亂。例如,一個進程預期的網絡數據可能會被另外一個進程讀取。或者多個進程可能嘗試在磁盤的相同位置儲存數據。操做系統負責經過提供合適的抽象來維持秩序。
做爲程序員,你不須要知道太多關於這些功能如何實現的事情。可是若是你很好奇,你能夠在這個屏蔽層的後面發現一大堆有趣的事情。並且,若是你知道其中所發生的事情,你會成爲更好的程序員。
當我寫這本書的時候,我最關注的進程就是個人文本編輯器,Emacs。偶爾我也會切換到終端窗口,它是一個運行Unix shell並提供命令行接口的窗口。
當我移動鼠標時,窗口的管理器會被喚醒,看到鼠標在終端窗口上方,而且喚醒終端。終端又喚醒shell。若是我在shell中鍵入make
,它就會建立一個新的進程來運行Make。Make會建立另外一個進程來運行LaTeX,以後另外一個進程會顯示結果。
若是我須要查詢一些東西,我會切換到另外一個桌面,這會再次喚醒窗口管理器。若是我點擊Web瀏覽器的圖標,窗口管理器會建立進行來運行Web瀏覽器。許多瀏覽器,相似Chrome,會爲每一個窗口和每一個選項卡建立新的進程。
而且這些只是我所瞭解的進程,同時還有許多其它進程「在後臺」運行。它們中許多都在執行操做系統相關的工做。
Unix命令ps
能打印出運行中進程的信息。若是你在終端裏運行它,可能會看到這些:
PID TTY TIME CMD 2687 pts/1 00:00:00 bash 2801 pts/1 00:01:24 emacs 24762 pts/1 00:00:00 ps
第一列是惟一的進程ID。第二列是建立進程的終端,「TTY」表明「電傳打字機」(Teletypewriter),它是原始的機械終端。
第三行是用於該進程的處理器時間總計,依次爲時、分、秒。最後一行是所運行進程的名稱。這個例子中,bash
是shell的名稱,用於解釋我鍵入到終端中的命令。Emacs是個人文本編輯器,而ps
是生成這份輸出的程序。
一般,ps
只會列出有關當前終端的進程。若是你使用-e
選項,你會獲得全部進程(也包括屬於其餘用戶的進程,我認爲這是個安全缺陷)。
在個人系統上有233個進程,下面是它們的一部分:
PID TTY TIME CMD 1 ? 00:00:17 init 2 ? 00:00:00 kthreadd 3 ? 00:00:02 ksoftirqd/0 4 ? 00:00:00 kworker/0:0 8 ? 00:00:00 migration/0 9 ? 00:00:00 rcu_bh 10 ? 00:00:16 rcu_sched 47 ? 00:00:00 cpuset 48 ? 00:00:00 khelper 49 ? 00:00:00 kdevtmpfs 50 ? 00:00:00 netns 51 ? 00:00:00 bdi-default 52 ? 00:00:00 kintegrityd 53 ? 00:00:00 kblockd 54 ? 00:00:00 ata_sff 55 ? 00:00:00 khubd 56 ? 00:00:00 md 57 ? 00:00:00 devfreq_wq
init
是操做系統啓動時首先建立的進程。它又會建立許多其它進程,以後會閒置,直到它建立的進程運行完畢。
kthreadd
是操做系統用於建立新的「線程」的進程。以後咱們將會談論更多關於線程的東西,可是你暫時你能夠認爲線程是一種進程。