自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

這些操作系統(tǒng)的概念,保你沒聽過!

系統(tǒng)
大部分操作系統(tǒng)提供了特定的基礎概念和抽象,例如進程、地址空間、文件等,它們是需要理解的核心內(nèi)容。下面我們會簡要介紹一些基本概念,

 

 

[[314476]]

 

操作系統(tǒng)概念

大部分操作系統(tǒng)提供了特定的基礎概念和抽象,例如進程、地址空間、文件等,它們是需要理解的核心內(nèi)容。下面我們會簡要介紹一些基本概念,為了說明這些概念,我們會不時的從 UNIX 中提出示例,相同的示例也會存在于其他系統(tǒng)中,我們后面會進行介紹。

進程

操作系統(tǒng)一個很關鍵的概念就是 進程(Process)。進程的本質(zhì)就是操作系統(tǒng)執(zhí)行的一個程序。與每個進程相關的是地址空間(address space),這是從某個最小值的存儲位置(通常是零)到某個最大值的存儲位置的列表。在這個地址空間中,進程可以進行讀寫操作。地址空間中存放有可執(zhí)行程序,程序所需要的數(shù)據(jù)和它的棧。與每個進程相關的還有資源集,通常包括寄存器(registers)(寄存器一般包括程序計數(shù)器(program counter)和堆棧指針(stack pointer))、打開文件的清單、突發(fā)的報警、有關的進程清單和其他需要執(zhí)行程序的信息。你可以把進程看作是容納運行一個程序所有信息的一個容器。

對進程建立一種直觀感覺的方式是考慮建立一種多程序的系統(tǒng)??紤]下面這種情況:用戶啟動一個視頻編輯程序,指示它按照某種格式轉(zhuǎn)換視頻,然后再去瀏覽網(wǎng)頁。同時,一個檢查電子郵件的后臺進程被喚醒并開始運行,這樣,我們目前就會有三個活動進程:視頻編輯器、Web 瀏覽器和電子郵件接收程序。操作系統(tǒng)周期性的掛起一個進程然后啟動運行另一個進程,這可能是由于過去一兩秒鐘程序用完了 CPU 分配的時間片,而 CPU 轉(zhuǎn)而運行另外的程序。

像這樣暫時中斷進程后,下次應用程序在此啟動時,必須要恢復到與中斷時刻相同的狀態(tài),這在我們用戶看起來是習以為常的事情,但是操作系統(tǒng)內(nèi)部卻做了巨大的事情。這就像和足球比賽一樣,一場完美精彩的比賽是可以忽略裁判的存在的。這也意味著在掛起時該進程的所有信息都要被保存下來。例如,進程可能打開了多個文件進行讀取。與每個文件相關聯(lián)的是提供當前位置的指針(即下一個需要讀取的字節(jié)或記錄的編號)。當進程被掛起時,必須要保存這些指針,以便在重新啟動進程后執(zhí)行的 read調(diào)用將能夠正確的讀取數(shù)據(jù)。在許多操作系統(tǒng)中,與一個進程有關的所有信息,除了該進程自身地址空間的內(nèi)容以外,均存放在操作系統(tǒng)的一張表中,稱為 進程表(process table),進程表是數(shù)組或者鏈表結(jié)構,當前存在每個進程都要占據(jù)其中的一項。

所以,一個掛起的進程包括:進程的地址空間(往往稱作磁芯映像, core image,紀念過去的磁芯存儲器),以及對應的進程表項(其中包括寄存器以及稍后啟動該進程所需要的許多其他信息)。

與進程管理有關的最關鍵的系統(tǒng)調(diào)用往往是決定著進程的創(chuàng)建和終止的系統(tǒng)調(diào)用。考慮一個典型的例子,有一個稱為 命令解釋器(command interpreter) 或 shell 的進程從終端上讀取命令。此時,用戶剛鍵入一條命令要求編譯一個程序。shell 必須先創(chuàng)建一個新進程來執(zhí)行編譯程序,當編譯程序結(jié)束時,它執(zhí)行一個系統(tǒng)調(diào)用來終止自己的進程。

如果一個進程能夠創(chuàng)建一個或多個進程(稱為子進程),而且這些進程又可以創(chuàng)建子進程,則很容易找到進程數(shù),如下所示

 

 

 

 

上圖表示一個進程樹的示意圖,進程 A 創(chuàng)建了兩個子進程 B 和進程 C,子進程 B 又創(chuàng)建了三個子進程 D、E、F。

合作完成某些作業(yè)的相關進程經(jīng)常需要彼此通信來完成作業(yè),這種通信稱為進程間通信(interprocess communication)。我們在后面會探討進程間通信。

其他可用的進程系統(tǒng)調(diào)用包括:申請更多的內(nèi)存(或釋放不再需要的內(nèi)存),等待一個子進程結(jié)束,用另一個程序覆蓋該程序。

有時,需要向一個正在運行的進程傳遞信息,而該進程并沒有等待接收信息。例如,一個進程通過網(wǎng)絡向另一臺機器上的進程發(fā)送消息進行通信。為了保證一條消息或消息的應答不丟失。發(fā)送者要求它所在的操作系統(tǒng)在指定的若干秒后發(fā)送一個通知,這樣如果對方尚未收到確認消息就可以進行重新發(fā)送。在設定該定時器后,程序可以繼續(xù)做其他工作。

在限定的時間到達后,操作系統(tǒng)會向進程發(fā)送一個 警告信號(alarm signal)。這個信號引起該進程暫時掛起,無論該進程正在做什么,系統(tǒng)將其寄存器的值保存到堆棧中,并開始重新啟動一個特殊的信號處理程,比如重新發(fā)送可能丟失的消息。這些信號是軟件模擬的硬件中斷,除了定時器到期之外,該信號可以通過各種原因產(chǎn)生。許多由硬件檢測出來的陷阱,如執(zhí)行了非法指令或使用了無效地址等,也被轉(zhuǎn)換成該信號并交給這個進程。

系統(tǒng)管理器授權每個進程使用一個給定的 UID(User IDentification)。每個啟動的進程都會有一個操作系統(tǒng)賦予的 UID,子進程擁有與父進程一樣的 UID。用戶可以是某個組的成員,每個組也有一個 GID(Group IDentification)。

在 UNIX 操作系統(tǒng)中,有一個 UID 是 超級用戶(superuser),或者 Windows 中的管理員(administrator),它具有特殊的權利,可以違背一些保護規(guī)則。在大型系統(tǒng)中,只有系統(tǒng)管理員掌握著那些用戶可以稱為超級用戶。

地址空間

每臺計算機都有一些主存用來保存正在執(zhí)行的程序。在一個非常簡單的操作系統(tǒng)中,僅僅有一個應用程序運行在內(nèi)存中。為了運行第二個應用程序,需要把第一個應用程序移除才能把第二個程序裝入內(nèi)存。

復雜一些的操作系統(tǒng)會允許多個應用程序同時裝入內(nèi)存中運行。為了防止應用程序之間相互干擾(包括操作系統(tǒng)),需要有某種保護機制。雖然此機制是在硬件中實現(xiàn),但卻是由操作系統(tǒng)控制的。

上述觀點涉及對計算機主存的管理和保護。另一種同等重要并與存儲器有關的內(nèi)容是管理進程的地址空間。通常,每個進程有一些可以使用的地址集合,典型值從 0 開始直到某個最大值。一個進程可擁有的最大地址空間小于主存。在這種情況下,即使進程用完其地址空間,內(nèi)存也會有足夠的內(nèi)存運行該進程。

但是,在許多 32 位或 64 位地址的計算機中,分別有 2^32 或 2^64 字節(jié)的地址空間。如果一個進程有比計算機擁有的主存還大的地址空間,而且該進程希望使用全部的內(nèi)存,那該怎么處理?在早期的計算機中是無法處理的。但是現(xiàn)在有了一種虛擬內(nèi)存的技術,正如前面講到過的,操作系統(tǒng)可以把部分地址空間裝入主存,部分留在磁盤上,并且在需要時來回交換它們。

文件

幾乎所有操作系統(tǒng)都支持的另一個關鍵概念就是文件系統(tǒng)。如前所述,操作系統(tǒng)的一項主要功能是屏蔽磁盤和其他 I/O 設備的細節(jié)特性,給程序員提供一個良好、清晰的獨立于設備的抽象文件模型。創(chuàng)建文件、刪除文件、讀文件和寫文件 都需要系統(tǒng)調(diào)用。在文件可以讀取之前,必須先在磁盤上定位和打開文件,在文件讀過之后應該關閉該文件,有關的系統(tǒng)調(diào)用則用于完成這類操作。

為了提供保存文件的地方,大多數(shù)個人計算機操作系統(tǒng)都有目錄(directory) 的概念,從而可以把文件分組。比如,學生可以給每個課程都創(chuàng)建一個目錄,用于保存該學科的資源,另一個目錄可以存放電子郵件,再有一個目錄可以存放萬維網(wǎng)主頁。這就需要系統(tǒng)調(diào)用創(chuàng)建和刪除目錄、將已有文件放入目錄中,從目錄中刪除文件等。目錄項可以是文件或者目錄,目錄和目錄之間也可以嵌套,這樣就產(chǎn)生了文件系統(tǒng)

 

 

 

 

進程和文件層次都是以樹狀的結(jié)構組織,但這兩種樹狀結(jié)構有不少不同之處。一般進程的樹狀結(jié)構層次不深(很少超過三層),而文件系統(tǒng)的樹狀結(jié)構要深一些,通常會到四層甚至五層。進程樹層次結(jié)構是暫時的,通常最多存在幾分鐘,而目錄層次則可能存在很長時間。進程和文件在權限保護方面也是有區(qū)別的。一般來說,父進程能控制和訪問子進程,而在文件和目錄中通常存在一種機制,使文件所有者之外的其他用戶也能訪問該文件。

目錄層結(jié)構中的每一個文件都可以通過從目錄的頂部即 根目錄(Root directory) 開始的路徑名(path name) 來確定。絕對路徑名包含了從根目錄到該文件的所有目錄清單,它們之間用斜杠分隔符分開,在上面的大學院系文件系統(tǒng)中,文件 CS101 的路徑名是 /Faculty/Prof.Brown/Courses/CS101。最開始的斜杠分隔符代表的是根目錄 /,也就是文件系統(tǒng)的絕對路徑。

“出于歷史原因,Windows 下面的文件系統(tǒng)以 \ 來作為分隔符,但是 Linux 會以 / 作為分隔符。

在上面的系統(tǒng)中,每個進程會有一個 工作目錄(working directory),對于沒有以斜線開頭給出絕對地址的路徑,將在這個工作目錄下尋找。如果 /Faculty/Prof.Brown 是工作目錄,那么 /Courses/CS101 與上面給定的絕對路徑名表示的是同一個文件。進程可以通過使用系統(tǒng)調(diào)用指定新的工作目錄,從而變更其工作目錄。

在讀寫文件之前,首先需要打開文件,檢查其訪問權限。若權限許可,系統(tǒng)將返回一個小整數(shù),稱作文件描述符(file descriptor),供后續(xù)操作使用。若禁止訪問,系統(tǒng)則返回一個錯誤碼。

在 UNIX 中,另一個重要的概念是 特殊文件(special file)。提供特殊文件是為了使 I/O 設備看起來像文件一般。這樣,就像使用系統(tǒng)調(diào)用讀寫文件一樣,I/O 設備也可以通過同樣的系統(tǒng)調(diào)用進行讀寫。特殊文件有兩種,一種是塊兒特殊文件(block special file) 和 字符特殊文件(character special file)。塊特殊文件指那些由可隨機存取的塊組成的設備,如磁盤等。比如打開一個塊特殊文件,然后讀取第4塊,程序可以直接訪問設備的第4塊而不必考慮存放在該文件的文件系統(tǒng)結(jié)構。類似的,字符特殊文件用于打印機、調(diào)制解調(diào)器和其他接受或輸出字符流的設備。按照慣例,特殊文件保存在 /dev 目錄中。例如,/devv/lp 是打印機。

還有一種與進程和文件相關的特性是管道,管道(pipe) 是一種虛文件,他可以連接兩個進程

 

 

 

 

如果 A 和 B 希望通過管道對話,他們必須提前設置管道。當進程 A 相對進程 B 發(fā)送數(shù)據(jù)時,它把數(shù)據(jù)寫到管道上,相當于管道就是輸出文件。這樣,在 UNIX 中兩個進程之間的通信就非常類似于普通文件的讀寫了。

保護

計算機中含有大量的信息,用戶希望能夠?qū)@些信息中有用而且重要的信息加以保護,這些信息包括電子郵件、商業(yè)計劃等,管理這些信息的安全性完全依靠操作系統(tǒng)來保證。例如,文件提供授權用戶訪問。

比如 UNIX 操作系統(tǒng),UNIX 操作系統(tǒng)通過對每個文件賦予一個 9 位二進制保護代碼,對 UNIX 中的文件實現(xiàn)保護。該保護代碼有三個位子段,一個用于所有者,一個用于與所有者同組(用戶被系統(tǒng)管理員劃分成組)的其他成員,一個用于其他人。每個字段中有一位用于讀訪問,一位用于寫訪問,一位用于執(zhí)行訪問。這些位就是著名的 rwx位。例如,保護代碼 rwxr-x--x 的含義是所有者可以讀、寫或執(zhí)行該文件,其他的組成員可以讀或執(zhí)行(但不能寫)此文件、而其他人可以執(zhí)行(但不能讀和寫)該文件。

shell

操作系統(tǒng)是執(zhí)行系統(tǒng)調(diào)用的代碼。編輯器、編譯器、匯編程序、鏈接程序、使用程序以及命令解釋符等,盡管非常重要,非常有用,但是它們確實不是操作系統(tǒng)的組成部分。下面我們著重介紹一下 UNIX 下的命令提示符,也就是 shell,shell 雖然有用,但它也不是操作系統(tǒng)的一部分,然而它卻能很好的說明操作系統(tǒng)很多特性,下面我們就來探討一下。

shell 有許多種,例如 sh、csh、ksh 以及 bash等,它們都支持下面這些功能,最早起的 shell 可以追溯到 sh

用戶登錄時,會同時啟動一個 shell,它以終端作為標準輸入和標準輸出。首先顯示提示符(prompt),它可能是一個美元符號($),提示用戶 shell 正在等待接收命令,假如用戶輸入

date

shell 會創(chuàng)建一個子進程,并運行 date 做為子進程。在該子進程運行期間,shell 將等待它結(jié)束。在子進程完成時,shell 會顯示提示符并等待下一行輸入。

用戶可以將標準輸出重定向到一個文件中,例如

date > file

同樣的,也可以將標準輸入作為重定向

sort file2

這會調(diào)用 sort 程序來接收 file1 的內(nèi)容并把結(jié)果輸出到 file2。

可以將一個應用程序的輸出通過管道作為另一個程序的輸入,因此有

cat file1 file2 file3 | sort > /dev/lp

這會調(diào)用 cat 應用程序來合并三個文件,將其結(jié)果輸送到 sort 程序中并按照字典進行排序。sort 應用程序又被重定向到 /dev/lp ,顯然這是一個打印操作。

系統(tǒng)調(diào)用

我們已經(jīng)可以看到操作系統(tǒng)提供了兩種功能:為用戶提供應用程序抽象和管理計算機資源。對于大部分在應用程序和操作系統(tǒng)之間的交互主要是應用程序的抽象,例如創(chuàng)建、寫入、讀取和刪除文件。計算機的資源管理對用戶來說基本上是透明的。因此,用戶程序和操作系統(tǒng)之間的接口主要是處理抽象。為了真正理解操作系統(tǒng)的行為,我們必須仔細的分析這個接口。

多數(shù)現(xiàn)代操作系統(tǒng)都有功能相同但是細節(jié)不同的系統(tǒng)調(diào)用,引發(fā)操作系統(tǒng)的調(diào)用依賴于計算機自身的機制,而且必須用匯編代碼表達。任何單 CPU 計算機一次執(zhí)行執(zhí)行一條指令。如果一個進程在用戶態(tài)下運行用戶程序,例如從文件中讀取數(shù)據(jù)。那么如果想要把控制權交給操作系統(tǒng)控制,那么必須執(zhí)行一個異常指令或者系統(tǒng)調(diào)用指令。操作系統(tǒng)緊接著需要參數(shù)檢查找出所需要的調(diào)用進程。操作系統(tǒng)緊接著進行參數(shù)檢查找出所需要的調(diào)用進程。然后執(zhí)行系統(tǒng)調(diào)用,把控制權移交給系統(tǒng)調(diào)用下面的指令。大致來說,系統(tǒng)調(diào)用就像是執(zhí)行了一個特殊的過程調(diào)用,但是只有系統(tǒng)調(diào)用能夠進入內(nèi)核態(tài)而過程調(diào)用則不能進入內(nèi)核態(tài)。

為了能夠了解具體的調(diào)用過程,下面我們以 read 方法為例來看一下調(diào)用過程。像上面提到的那樣,會有三個參數(shù),第一個參數(shù)是指定文件、第二個是指向緩沖區(qū)、第三個參數(shù)是給定需要讀取的字節(jié)數(shù)。就像幾乎所有系統(tǒng)調(diào)用一樣,它通過使用與系統(tǒng)調(diào)用相同的名稱來調(diào)用一個函數(shù)庫,從而從C程序中調(diào)用:read。

count = read(fd,buffer,nbytes);

系統(tǒng)調(diào)用在 count 中返回實際讀出的字節(jié)數(shù)。這個值通常與 nbytes 相同,但也可能更小。比如在讀過程中遇到了文件尾的情況。

如果系統(tǒng)調(diào)用不能執(zhí)行,不管是因為無效的參數(shù)還是磁盤錯誤,count 的值都會被置成 -1,然后在全局變量 errno 中放入錯誤信號。程序應該進場檢查系統(tǒng)調(diào)用的結(jié)果以了解是否出錯。

系統(tǒng)調(diào)用是通過一系列的步驟實現(xiàn)的,為了更清楚的說明這個概念,我們還以 read 調(diào)用為例,在準備系統(tǒng)調(diào)用前,首先會把參數(shù)壓入堆棧,如下所示

 

 

 

 

C 和 C++ 編譯器使用逆序(必須把第一個參數(shù)賦值給 printf(格式字符串),放在堆棧的頂部)。第一個參數(shù)和第三個參數(shù)都是值調(diào)用,但是第二個參數(shù)通過引用傳遞,即傳遞的是緩沖區(qū)的地址(由 & 指示),而不是緩沖的內(nèi)容。然后是 C 調(diào)用系統(tǒng)庫的 read 函數(shù),這也是第四步。

在由匯編語言寫成的庫過程中,一般把系統(tǒng)調(diào)用的編號放在操作系統(tǒng)所期望的地方,如寄存器(第五步)。然后執(zhí)行一個 TRAP 指令,將用戶態(tài)切換到內(nèi)核態(tài),并在內(nèi)核中的一個固定地址開始執(zhí)行第六步。TRAP 指令實際上與過程調(diào)用指令非常相似,它們后面都跟隨一個來自遠處位置的指令,以及供以后使用的一個保存在棧中的返回地址。

TRAP 指令與過程調(diào)用指令存在兩個方面的不同

  • TRAP 指令會改變操作系統(tǒng)的狀態(tài),由用戶態(tài)切換到內(nèi)核態(tài),而過程調(diào)用不改變模式
  • 其次,TRAP 指令不能跳轉(zhuǎn)到任意地址上。根據(jù)機器的體系結(jié)構,要么跳轉(zhuǎn)到一個單固定地址上,或者指令中有一 8 位長的字段,它給定了內(nèi)存中一張表格的索引,這張表格中含有跳轉(zhuǎn)地址,然后跳轉(zhuǎn)到指定地址上。

跟隨在 TRAP 指令后的內(nèi)核代碼開始檢查系統(tǒng)調(diào)用編號,然后dispatch給正確的系統(tǒng)調(diào)用處理器,這通常是通過一張由系統(tǒng)調(diào)用編號所引用的、指向系統(tǒng)調(diào)用處理器的指針表來完成第七步。此時,系統(tǒng)調(diào)用處理器運行第八步,一旦系統(tǒng)調(diào)用處理器完成工作,控制權會根據(jù) TRAP 指令后面的指令中返回給函數(shù)調(diào)用庫第九步。這個過程接著以通常的過程調(diào)用返回的方式,返回到客戶應用程序,這是第十步。然后調(diào)用完成后,操作系統(tǒng)還必須清除用戶堆棧,然后增加堆棧指針(increment stackpointer),用來清除調(diào)用 read 之前壓入的參數(shù)。從而完成整個 read 調(diào)用過程。

在上面的第九步中我們說道,控制可能返回 TRAP 指令后面的指令,把控制權再移交給調(diào)用者這個過程中,系統(tǒng)調(diào)用會發(fā)生阻塞,從而避免應用程序繼續(xù)執(zhí)行。這么做是有原因的。例如,如果試圖讀鍵盤,此時并沒有任何輸入,那么調(diào)用者就必須被阻塞。在這種情形下,操作系統(tǒng)會檢查是否有其他可以運行的進程。這樣,當有用戶輸入 時候,進程會提醒操作系統(tǒng),然后返回第 9 步繼續(xù)運行。

下面,我們會列出一些常用的 POSIX 系統(tǒng)調(diào)用,POSIX 系統(tǒng)調(diào)用大概有 100 多個,它們之中最重要的一些調(diào)用見下表

進程管理

 

 

 

 

文件管理

 

 

 

 

目錄和文件系統(tǒng)管理

 

 

 

 

其他

 

 

 

 

上面的系統(tǒng)調(diào)用參數(shù)中有一些公共部分,例如 pid 系統(tǒng)進程 id,fd 是文件描述符,n 是字節(jié)數(shù),position 是在文件中的偏移量、seconds 是流逝時間。

從宏觀角度上看,這些系統(tǒng)調(diào)所提供的服務確定了多數(shù)操作系統(tǒng)應該具有的功能,下面分別來對不同的系統(tǒng)調(diào)用進行解釋

用于進程管理的系統(tǒng)調(diào)用

在 UNIX 中,fork 是唯一可以在 POSIX 中創(chuàng)建進程的途徑,它創(chuàng)建一個原有進程的副本,包括所有的文件描述符、寄存器等內(nèi)容。在 fork 之后,原有進程以及副本(父與子)就分開了。在 fork 過程中,所有的變量都有相同的值,雖然父進程的數(shù)據(jù)通過復制給子進程,但是后續(xù)對其中任何一個進程的修改不會影響到另外一個。fork 調(diào)用會返回一個值,在子進程中該值為 0 ,并且在父進程中等于子進程的 進程標識符(Process IDentified,PID)。使用返回的 PID,就可以看出來哪個是父進程和子進程。

 

 

 

 

在多數(shù)情況下, 在 fork 之后,子進程需要執(zhí)行和父進程不一樣的代碼。從終端讀取命令,創(chuàng)建一個子進程,等待子進程執(zhí)行命令,當子進程結(jié)束后再讀取下一個輸入的指令。為了等待子進程完成,父進程需要執(zhí)行 waitpid 系統(tǒng)調(diào)用,父進程會等待直至子進程終止(若有多個子進程的話,則直至任何一個子進程終止)。waitpid 可以等待一個特定的子進程,或者通過將第一個參數(shù)設為 -1 的方式,等待任何一個比較老的子進程。當 waitpid 完成后,會將第二個參數(shù) statloc 所指向的地址設置為子進程的退出狀態(tài)(正?;虍惓=K止以及退出值)。有各種可使用的選項,它們由第三個參數(shù)確定。例如,如果沒有已經(jīng)退出的子進程則立刻返回。

那么 shell 該如何使用 fork 呢?在鍵入一條命令后,shell 會調(diào)用 fork 命令創(chuàng)建一個新的進程。這個子進程會執(zhí)行用戶的指令。通過使用 execve 系統(tǒng)調(diào)用可以實現(xiàn)系統(tǒng)執(zhí)行,這個系統(tǒng)調(diào)用會引起整個核心映像被一個文件所替代,該文件由第一個參數(shù)給定。下面是一個簡化版的例子說明 fork、waitpid 和 execve 的使用

  1. #define TRUE 1 
  2.  
  3. while(TRUE){                                            /* 一直循環(huán)下去 */ 
  4.     type_prompt();                                  /* 在屏幕上顯示提示符 */ 
  5.     read_command(command,parameters)                    /* 從終端讀取輸入 */ 
  6.     if(fork() != 0){                                        /* fork 子進程 */ 
  7.         /* 父代碼 */ 
  8.         waitpid(-1, &status, 0);                            /* 等待子進程執(zhí)行完畢 */ 
  9.     }else
  10.         /* 子代碼 */ 
  11.         execve(command,parameters,0)                    /* 執(zhí)行命令 */ 
  12.     } 

 

一般情況下,execve 有三個參數(shù):將要執(zhí)行的文件名稱,一個指向變量數(shù)組的指針,以及一個指向環(huán)境數(shù)組的指針。這里對這些參數(shù)做一個簡要的說明。

先看一個 shell 指令

cp file1 file2

此命令把 file1 復制到 file2 文件中,在 shell 執(zhí)行 fork 之后,子進程定位并執(zhí)行文件拷貝,并將源文件和目標文件的名稱傳遞給它。

cp 的主程序(以及包含其他大多數(shù) C 程序的主程序)包含聲明

main(argc,argv,envp)

其中 argc 是命令行中參數(shù)數(shù)目的計數(shù),包括程序名稱。對于上面的例子,argc 是3。第二個參數(shù)argv 是數(shù)組的指針。該數(shù)組的元素 i 是指向該命令行第 i 個字符串的指針。在上面的例子中,argv[0] 指向字符串 cp,argv[1] 指向字符串 file1,argv[2] 指向字符串 file2。main 的第三個參數(shù)是指向環(huán)境的指針,該環(huán)境是一個數(shù)組,含有 name = value 的賦值形式,用以將諸如終端類型以及根目錄等信息傳送給程序。這些變量通常用來確定用戶希望如何完成特定的任務(例如,使用默認打印機)。在上面的例子中,沒有環(huán)境參數(shù)傳遞給 execve ,所以環(huán)境變量是 0 ,所以 execve 的第三個參數(shù)為 0 。

可能你覺得 execve 過于復雜,這時候我要鼓勵一下你,execve 可能是 POSIX 的全部系統(tǒng)調(diào)用中最復雜的一個了,其他都比較簡單。作為一個簡單的例子,我們再來看一下 exit ,這是進程在執(zhí)行完成后應執(zhí)行的系統(tǒng)調(diào)用。這個系統(tǒng)調(diào)用有一個參數(shù),它的退出狀態(tài)是 0 - 255 之間,它通過 waitpid 系統(tǒng)調(diào)用中的 statloc 返回給父級。

UNIX 中的進程將內(nèi)存劃分成三個部分:text segment,文本區(qū),例如程序代碼,data segment,數(shù)據(jù)區(qū),例如變量,stack segment,棧區(qū)域。數(shù)據(jù)向上增長而堆棧向下增長,如下圖所示

 

 

 

 

上圖能說明三個部分的內(nèi)存分配情況,夾在中間的是空閑區(qū),也就是未分配的區(qū)域,堆棧在需要時自動的擠壓空閑區(qū)域,不過數(shù)據(jù)段的擴展是顯示地通過系統(tǒng)調(diào)用 brk 進行的,在數(shù)據(jù)段擴充后,該系統(tǒng)調(diào)用指向一個新地址。但是,這個調(diào)用不是 POSIX 標準中定義的,對于存儲器的動態(tài)分配,鼓勵程序員使用 malloc 函數(shù),而 malloc 的內(nèi)部實現(xiàn)則不是一個適合標準化的主題,因為幾乎沒有程序員直接使用它。

用于文件管理的系統(tǒng)調(diào)用

許多系統(tǒng)調(diào)用都與文件系統(tǒng)有關,要讀寫一個文件,必須先將其打開。這個系統(tǒng)調(diào)用通過絕對路徑名或指向工作目錄的相對路徑名指定要打開文件的名稱,而代碼 O_RDONLY、 O_WRONLY 或 O_RDWR 的含義分別是只讀、只寫或者兩者都可以,為了創(chuàng)建一個新文件,使用 O_CREATE 參數(shù)。然后可使用返回的文件描述符進行讀寫操作。接著,可以使用 close 關閉文件,這個調(diào)用使得文件描述符在后續(xù)的 open 中被再次使用。

最常用的調(diào)用還是 read 和 write,我們再前面探討過 read 調(diào)用,write 具有與 read 相同的參數(shù)。

盡管多數(shù)程序頻繁的讀寫文件,但是仍有一些應用程序需要能夠隨機訪問一個文件的任意部分。與每個文件相關的是一個指向文件當前位置的指針。在順序讀寫時,該指針通常指向要讀出(寫入)的下一個字節(jié)。Iseek 調(diào)用可以改變該位置指針的值,這樣后續(xù)的 read 或 write 調(diào)用就可以在文件的任何地方開始。

Iseek 有三個參數(shù),position = iseek(fd,offset,whence),第一個是文件描述符,第二個是文件位置,第三個是說明該文件位置是相對于文件起始位置,當前位置還是文件的結(jié)尾。在修改了指針之后,Iseek 所返回的值是文件中的絕對位置。

UNIX 為每個文件保存了該文件的類型(普通文件、特殊文件、目錄等)、大小,最后修改時間以及其他信息,程序可以通過 stat 系統(tǒng)調(diào)用查看這些信息。s = stat(name,&buf),第一個參數(shù)指定了被檢查的文件;第二個參數(shù)是一個指針,該指針指向存放這些信息的結(jié)構。對于一個打開的文件而言,fstat 調(diào)用完成同樣的工作。

用于目錄管理的系統(tǒng)調(diào)用

下面我們探討目錄和整個文件系統(tǒng)的系統(tǒng)調(diào)用,上面探討的是和某個文件有關的系統(tǒng)調(diào)用。mkdir 和 rmdir 分別用于創(chuàng)建s = mkdir(nname,mode) 和刪除 s = rmdir(name) 空目錄,下一個調(diào)用是 s = link(name1,name2) 它的作用是允許同一個文件以兩個或者多個名稱出現(xiàn),多數(shù)情況下是在不同的目錄中使用 link ,下面我們探討一下 link 是如何工作的

 

 

 

 

圖中有兩個用戶 ast 和 jim,每個用戶都有他自己的一個目錄和一些文件,如果 ast 要執(zhí)行一個包含下面系統(tǒng)調(diào)用的應用程序

link("/usr/jim/memo", "/usr/ast/note");

jim 中的 memo 文件現(xiàn)在會進入到 ast 的目錄中,在 note 名稱下。此后,/usr/jim/memo和 /usr/ast/note 會有相同的名稱。

“用戶目錄是保存在 /usr,/user,/home 還是其他位置,都是由本地系統(tǒng)管理員決定的。

要理解 link 是如何工作的需要清楚 link 做了什么操作。UNIX 中的每個文件都有一個獨一無二的版本,也稱作 i - number,i-編號,它標示著不同文件的版本。這個 i - 編號是 i-nodes,i-節(jié)點表的索引。每個文件都會表明誰擁有這個文件,這個磁盤塊的位置在哪,等等。目錄只是一個包含一組(i編號,ASCII名稱)對應的文件。UNIX 中的第一個版本中,每個目錄項都會有 16 個字節(jié),2 個字節(jié)對應 i - 編號和 14 個字節(jié)對應其名稱?,F(xiàn)在需要一個更復雜的結(jié)構需要支持長文件名,但是從概念上講一個目錄仍是一系列(i-編號,ASCII 名稱)的集合。在上圖中,mail 的 i-編號為 16,依此類推。link 只是利用某個已有文件的 i-編號,創(chuàng)建一個新目錄項(也許用一個新名稱)。在上圖 b 中,你會發(fā)現(xiàn)有兩個相同的 70 i-編號的文件,因此它們需要有相同的文件。如果其中一個使用了 unlink 系統(tǒng)調(diào)用的話,其中一個會被移除,另一個將保留。如果兩個文件都移除了,則 UNIX 會發(fā)現(xiàn)該文件不存在任何沒有目錄項(i-節(jié)點中的一個域記錄著指向該文件的目錄項),就會把該文件從磁盤中移除。

就像我們上面提到過的那樣,mount 系統(tǒng) s = mount(special,name,flag) 調(diào)用會將兩個文件系統(tǒng)合并為一個。通常的情況是將根文件系統(tǒng)分布在硬盤(子)分區(qū)上,并將用戶文件分布在另一個(子)分區(qū)上,該根文件系統(tǒng)包含常用命令的二進制(可執(zhí)行)版本和其他使用頻繁的文件。然后,用戶就會插入可讀取的 USB 硬盤。

通過執(zhí)行 mount 系統(tǒng)調(diào)用,USB 文件系統(tǒng)可以被添加到根文件系統(tǒng)中,

 

 

 

 

圖 a 是安裝前的系統(tǒng)文件,圖 b 是安裝后的系統(tǒng)文件。

如果用 C 語言來執(zhí)行那就是

mount("/dev/sdb0","/mnt",0)

這里,第一個參數(shù)是 USB 驅(qū)動器 0 的塊特殊文件名稱,第二個參數(shù)是被安裝在樹中的位置,第三個參數(shù)說明將要安裝的文件系統(tǒng)是可讀寫的還是只讀的。

當不再需要一個文件系統(tǒng)時,可以使用 umount 移除之。

其他系統(tǒng)調(diào)用

除了進程、文件、目錄系統(tǒng)調(diào)用,也存在其他系統(tǒng)調(diào)用的情況,下面我們來探討一下。我們可以看到上面其他系統(tǒng)調(diào)用只有四種,首先來看第一個 chdir,chdir 調(diào)用更改當前工作目錄,在調(diào)用

chdir("/usr/ast/test");

后,打開 xyz 文件,會打開 /usr/ast/test/xyz 文件,工作目錄的概念消除了總是需要輸入長文件名的需要。

在 UNIX 系統(tǒng)中,每個文件都會有保護模式,這個模式會有一個讀-寫-執(zhí)行位,它用來區(qū)分所有者、組和其他成員。chmod 系統(tǒng)調(diào)用提供改變文件模式的操作。例如,要使一個文件除了對所有者之外的用戶可讀,你可以執(zhí)行

chmod("file",0644);

kill 系統(tǒng)調(diào)用是用戶和用戶進程發(fā)送信號的方式,如果一個進程準備好捕捉一個特定的信號,那么在信號捕捉之前,會運行一個信號處理程序。如果進程沒有準備好捕捉特定的信號,那么信號的到來會殺掉該進程(此名字的由來)。

POSIX 定義了若干時間處理的進程。例如,time 以秒為單位返回當前時間,0 對應著 1970 年 1月 1日。在一臺 32 位字的計算機中,time 的最大值是 (2^32) - 1秒,這個數(shù)字對應 136 年多一點。所以在 2106 年,32 位的 UNIX 系統(tǒng)會發(fā)飆。如果讀者現(xiàn)在有 32 位 UNIX 系統(tǒng),建議在 2106 年更換位 64 位操作系統(tǒng)(偷笑~)。

Win 32 API

上面我們提到的都是 UNIX 系統(tǒng)調(diào)用,現(xiàn)在我們來聊聊 Win 32 中的系統(tǒng)調(diào)用。Windows 和 UNIX 在各自的編程方式上有著根本的不同。UNIX 程序由執(zhí)行某些操作或執(zhí)行其他操作的代碼組成,進行系統(tǒng)調(diào)用以執(zhí)行某些服務。Windows 系統(tǒng)則不同,Windows 應用程序通常是由事件驅(qū)動的。主程序會等待一些事件發(fā)生,然后調(diào)用程序去處理。最簡單的事件處理是鍵盤敲擊和鼠標滑過,或者是鼠標點擊,或者是插入 USB 驅(qū)動,然后操作系統(tǒng)調(diào)用處理器去處理事件,更新屏幕和更新程序內(nèi)部狀態(tài)。這是與 UNIX 不同的設計風格。

當然,Windows 也有系統(tǒng)調(diào)用。在 UNIX 中,系統(tǒng)調(diào)用(比如 read)和系統(tǒng)調(diào)用所使用的調(diào)用庫(例如 read)幾乎是一對一的關系。而在 Windows 中,情況則大不相同。首先,函數(shù)庫的調(diào)用和實際的系統(tǒng)調(diào)用幾乎是不對應的。微軟定義了一系列過程,稱為 Win32應用編程接口(Application Programming Interface),程序員通過這套標準的接口來實現(xiàn)系統(tǒng)調(diào)用。這個接口支持從 Windows 95 版本以來所有的 Windows 版本。

Win32 API 調(diào)用的數(shù)量是非常巨大的,有數(shù)千個多。但這些調(diào)用并不都是在內(nèi)核態(tài)的模式下運行時,有一些是在用戶態(tài)的模型下運行。Win32 API 有大量的調(diào)用,用來管理視窗、幾何圖形、文本、字體、滾動條、對話框、菜單以及 GUI 的其他功能。為了使圖形子系統(tǒng)在內(nèi)核態(tài)下運行,需要系統(tǒng)調(diào)用,否則就只有函數(shù)庫調(diào)用。

我們把關注點放在和 Win32 系統(tǒng)調(diào)用中來,我們可以簡單看一下 Win32 API 中的系統(tǒng)調(diào)用和 UNIX 中有什么不同(并不是所有的系統(tǒng)調(diào)用)

 

 

 

 

上表中是 UNIX 調(diào)用大致對應的 Win32 API 系統(tǒng)調(diào)用,簡述一下上表。CreateProcess 用于創(chuàng)建一個新進程,它把 UNIX 中的 fork 和 execve 兩個指令合成一個,一起執(zhí)行。它有許多參數(shù)用來指定新創(chuàng)建進程的性質(zhì)。Windows 中沒有類似 UNIX 中的進程層次,所以不存在父進程和子進程的概念。在進程創(chuàng)建之后,創(chuàng)建者和被創(chuàng)建者是平等的。WaitForSingleObject 用于等待一個事件,等待的事件可以是多種可能的事件。如果有參數(shù)指定了某個進程,那么調(diào)用者將等待指定的進程退出,這通過 ExitProcess 來完成。

然后是6個文件操作,在功能上和 UNIX 的調(diào)用類似,然而在參數(shù)和細節(jié)上是不同的。和 UNIX 中一樣,文件可以打開,讀取,寫入,關閉。SetFilePointer 和 GetFileAttributesEx 設置文件的位置并取得文件的屬性。

Windows 中有目錄,目錄分別用 CreateDirectory 以及 RemoveDirectory API 調(diào)用創(chuàng)建和刪除。也有對當前的目錄的標記,這可以通過 SetCurrentDirectory 來設置。使用GetLocalTime可獲得當前時間。

Win32 接口中沒有文件的鏈接、文件系統(tǒng)的 mount、umount 和 stat ,當然, Win32 中也有大量 UNIX 中沒有的系統(tǒng)調(diào)用,特別是對 GUI 的管理和調(diào)用。

操作系統(tǒng)結(jié)構

下面我們會探討操作系統(tǒng)的幾種結(jié)構,主要包括單體結(jié)構、分層系統(tǒng)、微內(nèi)核、客戶-服務端系統(tǒng)、虛擬機和外核等。下面以此來探討一下

單體系統(tǒng)

到目前為止,在大多數(shù)系統(tǒng)中,整個系統(tǒng)在內(nèi)核態(tài)以單一程序的方式運行。整個操作系統(tǒng)是以程序集合來編寫的,鏈接在一塊形成一個大的二進制可執(zhí)行程序。使用此技術時,如果系統(tǒng)中的每個過程都提供了前者所需的一些有用的計算,則它可以自由調(diào)用任何其他過程。在單體系統(tǒng)中,調(diào)用任何一個所需要的程序都非常高效,但是上千個不受限制的彼此調(diào)用往往非常臃腫和笨拙,而且單體系統(tǒng)必然存在單體問題,那就是只要系統(tǒng)發(fā)生故障,那么任何系統(tǒng)和應用程序?qū)⒉豢捎?,這往往是災難性的。

在單體系統(tǒng)中構造實際目標程序時,會首先編譯所有單個過程(或包含這些過程的文件),然后使用系統(tǒng)鏈接器將它們?nèi)拷壎ǖ揭粋€可執(zhí)行文件中

對于單體系統(tǒng),往往有下面幾種建議

  • 需要有一個主程序,用來調(diào)用請求服務程序
  • 需要一套服務過程,用來執(zhí)行系統(tǒng)調(diào)用
  • 需要一套服務程序,用來輔助服務過程調(diào)用

在單體系統(tǒng)中,對于每個系統(tǒng)調(diào)用都會有一個服務程序來保障和運行。需要一組實用程序來彌補服務程序需要的功能,例如從用戶程序中獲取數(shù)據(jù)??蓪⒏鞣N過程劃分為一個三層模型

 

 

 

 

除了在計算機初啟動時所裝載的核心操作系統(tǒng)外,許多操作系統(tǒng)還支持額外的擴展。比如 I/O 設備驅(qū)動和文件系統(tǒng)。這些部件可以按需裝載。在 UNIX 中把它們叫做 共享庫(shared library),在 Windows 中則被稱為 動態(tài)鏈接庫(Dynamic Link Library,DLL)。他們的擴展名為.dll,在 C:\Windows\system32 目錄下存在 1000 多個 DLL 文件,所以不要輕易刪除 C 盤文件,否則可能就炸了哦。

分層系統(tǒng)

分層系統(tǒng)使用層來分隔不同的功能單元。每一層只與該層的上層和下層通信。每一層都使用下面的層來執(zhí)行其功能。層之間的通信通過預定義的固定接口通信。

 

 

 

 

分層系統(tǒng)是由 E.W.Dijkstar 和他的學生在荷蘭技術學院所開發(fā)的 THE 系統(tǒng)。

把上面單體系統(tǒng)進一步通用化,就變?yōu)榱艘粋€層次式結(jié)構的操作系統(tǒng),它的上層軟件都是在下層軟件的基礎之上構建的。該系統(tǒng)分為六層,如下所示

處理器在 0 層運行,當中斷發(fā)生或定時器到期時,由該層完成進程切換;在第 0 層之上,系統(tǒng)由一些連續(xù)的進程組成,編寫這些進程時不用再考慮在單處理器上多進程運行的細節(jié)。內(nèi)存管理在第 1 層,它分配進程的主存空間。第 1 層軟件保證一旦需要訪問某一頁面,該頁面必定已經(jīng)在內(nèi)存中,并且在頁面不需要的時候?qū)⑵湟瞥觥?/p>

第 2 層處理進程與操作員控制臺(即用戶)之間的通信。第 3 層管理 I/O 設備和相關的信息流緩沖區(qū)。第 4 層是用戶程序?qū)樱脩舫绦虿挥每紤]進程、內(nèi)存、控制臺或 I/O 設備管理等細節(jié)。系統(tǒng)操作員在第 5 層。

微內(nèi)核

在分層方式中,設計者要確定在哪里劃分 內(nèi)核-用戶 的邊界。傳統(tǒng)上,所有的層都在內(nèi)核中,但是這樣做沒有必要。事實上,盡可能減少內(nèi)核態(tài)中功能可能是更好的做法。因為內(nèi)核中的錯誤很難處理,一旦內(nèi)核態(tài)中出錯誤會拖累整個系統(tǒng)。

所以,為了實現(xiàn)高可靠性,將操作系統(tǒng)劃分成小的、層級之間能夠更好定義的模塊是很有必要的,只有一個模塊 --- 微內(nèi)核 --- 運行在內(nèi)核態(tài),其余模塊可以作為普通用戶進程運行。由于把每個設備驅(qū)動和文件系統(tǒng)分別作為普通用戶進程,這些模塊中的錯誤雖然會使這些模塊崩潰,但是不會使整個系統(tǒng)死機。

MINIX 3 是微內(nèi)核的代表作,它的具體結(jié)構如下

 

 

 

 

在內(nèi)核的外部,系統(tǒng)的構造有三層,它們都在用戶態(tài)下運行,最底層是設備驅(qū)動器。由于它們都在用戶態(tài)下運行,所以不能物理的訪問 I/O 端口空間,也不能直接發(fā)出 I/O 命令。相反,為了能夠?qū)?I/O 設備編程,驅(qū)動器構建一個結(jié)構,指明哪個參數(shù)值寫到哪個 I/O 端口,并聲稱一個內(nèi)核調(diào)用,這樣就完成了一次調(diào)用過程。

位于用戶態(tài)的驅(qū)動程序上面是服務器層,包含有服務器,它們完成操作系統(tǒng)的多數(shù)工作。由一個或多個文件服務器管理著文件系統(tǒng),進程管理器創(chuàng)建、銷毀和管理進程。服務器中有一個特殊的服務器稱為 再生服務器(reincarnation server),它的任務就是檢查服務器和驅(qū)動程序的功能是否正確,一旦檢查出來錯誤,它就會補上去,無需用戶干預。這種方式使得系統(tǒng)具有可恢復性,并具有較高的可靠性。

微內(nèi)核中的內(nèi)核還具有一種 機制 與 策略 分離的思想。比如系統(tǒng)調(diào)度,一個比較簡單的調(diào)度算法是,對每個進程賦予一個優(yōu)先級,并讓內(nèi)核執(zhí)行具有最高優(yōu)先級的進程。這里,內(nèi)核機制就是尋找最高的優(yōu)先級進程并運行。而策略(賦予進程優(yōu)先級)可以在用戶態(tài)中的進程完成。在這種模式中,策略和機制是分離的,從而使內(nèi)核變得更小。

客戶-服務器模式

微內(nèi)核思想的策略是把進程劃分為兩類:服務器,每個服務器用來提供服務;客戶端,使用這些服務。這個模式就是所謂的 客戶-服務器模式。

客戶-服務器模式會有兩種載體,一種情況是一臺計算機既是客戶又是服務器,在這種方式下,操作系統(tǒng)會有某種優(yōu)化;但是普遍情況下是客戶端和服務器在不同的機器上,它們通過局域網(wǎng)或廣域網(wǎng)連接。

 

 

 

 

客戶通過發(fā)送消息與服務器通信,客戶端并不需要知道這些消息是在本地機器上處理,還是通過網(wǎng)絡被送到遠程機器上處理。對于客戶端而言,這兩種情形是一樣的:都是發(fā)送請求并得到回應。

越來越多的系統(tǒng),包括家里的 PC,都成為客戶端,而在某地運行的大型機器則成為服務器。許多 web 就是以這種方式運行的。一臺 PC 向某個服務器請求一個 Web 頁面,服務器把 Web 頁面返回給客戶端,這就是典型的客服-服務器模式

責任編輯:武曉燕 來源: Java建設者
相關推薦

2021-04-05 22:33:24

Windows 10Windows微軟

2019-09-23 14:38:51

人工智能AI無人機駕

2016-10-10 09:43:12

超融合超融合一體機

2015-01-07 09:53:03

蘋果喬布斯

2021-01-20 15:20:02

JS操作符前端

2010-04-15 15:21:43

Unix操作系統(tǒng)

2010-04-22 12:27:16

Aix操作系統(tǒng)

2010-04-15 17:21:40

Unix操作系統(tǒng)

2014-05-29 11:14:35

2018-04-02 10:54:31

Linux應用程序

2021-08-20 08:33:19

操作系統(tǒng)OS

2020-04-29 21:54:46

操作系統(tǒng)核心概念

2009-12-15 17:16:49

免費在線操作系統(tǒng)

2017-05-25 10:58:08

HBase數(shù)據(jù)庫操作系統(tǒng)

2010-01-06 15:36:30

Linux操作系統(tǒng)

2010-02-25 15:03:58

Linux操作系統(tǒng)

2010-01-06 16:32:45

Linux操作系統(tǒng)

2023-05-29 09:41:42

操作系統(tǒng)計算機系統(tǒng)

2017-11-30 10:26:32

操作系統(tǒng)運行時間CPU

2009-12-07 17:51:39

點贊
收藏

51CTO技術棧公眾號