操作系统学习总结(超赞!!!)
我是技術搬運工,好東西當然要和大家分享啦.原文地址
操作系統基本特征
1. 并發
并發性是指宏觀上在一段時間內能同時運行多個程序,而并行性則指同一時刻能運行多個指令。
并行需要硬件支持,如多流水線或者多處理器。
操作系統通過引入進程和線程,使得程序能夠并發運行。
2. 共享
共享是指系統中的資源可以供多個并發的進程共同使用。
有兩種共享方式:互斥共享和同時共享。
互斥共享的資源稱為臨界資源,例如打印機等,在同一時間只允許一個進程訪問,否則會出現錯誤,需要用同步機制來實現對臨界資源的訪問。
3. 虛擬
虛擬技術把一個物理實體轉換為多個邏輯實體。主要有兩種虛擬技術:時分復用技術和空分復用技術,例如多個進程能在同一個處理器上并發執行使用了時分復用技術,讓每個進程輪流占有處理器,每次只執行一小個時間片并快速切換,這樣就好像有多個處理器進行處理。
4. 異步
異步是指進程不是一次性執行完畢,而是走走停停,以不可知的速度向前推進。
系統調用
如果一個進程在用戶態需要用到操作系統的一些功能,就需要使用系統調用從而陷入內核,由操作系統代為完成。
可以由系統調用請求的功能有設備管理、文件管理、進程管理、進程通信、存儲器管理等。
中斷分類
1. 外中斷
由 CPU 執行指令以外的事件引起,如 I/O 結束中斷,表示設備輸入/輸出處理已經完成,處理器能夠發送下一個輸入/輸出請求。此外還有時鐘中斷、控制臺中斷等。
2. 異常
由 CPU 執行指令的內部事件引起,如非法操作碼、地址越界、算術溢出等。
3. 陷入
在用戶程序中使用系統調用。
大內核和微內核
1. 大內核
大內核是將操作系統功能作為一個緊密結合的整體放到內核,由于各模塊共享信息,因此有很高的性能。
2. 微內核
由于操作系統不斷復雜,因此將一部分操作系統功能移出內核,從而降低內核的復雜性。移出的部分根據分層的原則劃分成若干服務,相互獨立。但是需要頻繁地在用戶態和核心態之間進行切換,會有一定的性能損失。
第二章 進程管理
進程與線程
1. 進程
進程是操作系統進行資源分配的基本單位。
進程控制塊 (Process Control Block, PCB) 描述進程的基本信息和運行狀態,所謂的創建進程和撤銷進程,都是指對 PCB 的操作。
2. 線程
一個線程中可以有多個線程,是獨立調度的基本單位。同一個進程中的多個線程之間可以并發執行,它們共享進程資源。
3. 區別
① 擁有資源:進程是資源分配的基本單位,但是線程不擁有資源,線程可以訪問率屬進程的資源。
② 調度:線程是獨立調度的基本單位,在同一進程中,線程的切換不會引起進程切換,從一個進程內的線程切換到另一個進程中的線程時,會引起進程切換。
③ 系統開銷:由于創建或撤銷進程時,系統都要為之分配或回收資源,如內存空間、I/O 設備等,因此操作系統所付出的開銷遠大于創建或撤銷線程時的開銷。類似地,在進行進程切換時,涉及當前執行進程 CPU 環境的保存及新調度進程 CPU 環境的設置。而線程切換時只需保存和設置少量寄存器內容,開銷很小。此外,由于同一進程內的多個線程共享進程的地址空間,因此,這些線程之間的同步與通信非常容易實現,甚至無需操作系統的干預。
④ 通信方面:進程間通信 (IPC) 需要進程同步和互斥手段的輔助,以保證數據的一致性,而線程間可以通過直接讀/寫進程數據段(如全局變量)來進行通信。
舉例:QQ 和 瀏覽器是兩個進程,瀏覽器進程里面有很多線程,例如 http 請求線程、事件響應線程、渲染線程等等,線程的并發執行使得在瀏覽器中點擊一個新鏈接從而發起 http 請求時,瀏覽器還可以響應用戶的其它事件。
進程狀態的切換
阻塞狀態是缺少需要的資源從而由運行狀態轉換而來,但是該資源不包括 CPU,缺少 CPU 會讓進程從運行態轉換為就緒態。
只有就緒態和運行態可以相互轉換,其它的都是單向轉換。就緒狀態的進程通過調度算法從而獲得 CPU 時間,轉為運行狀態;而運行狀態的進程,在分配給它的 CPU 時間片用完之后就會轉為就緒狀態,等待下一次調度。
調度算法
需要針對不同環境來討論調度算法。
1. 批處理系統中的調度
1.1 先來先服務(FCFS)
first-come first-serverd。
調度最先進入就緒隊列的作業。
有利于長作業,但不利于短作業,因為短作業必須一直等待前面的長作業執行完畢才能執行,而長作業又需要執行很長時間,造成了短作業等待時間過長。
1.2 短作業優先(SJF)
shortest job first。
調度估計運行時間最短的作業。
長作業有可能會餓死,處于一直等待短作業執行完畢的狀態。如果一直有短作業到來,那么長作業永遠得不到調度。
1.3 最短剩余時間優先(SRTN)
shortest remaining time next。
2. 交互式系統中的調度
2.1 優先權優先
除了可以手動賦予優先權之外,還可以把響應比作為優先權,這種調度方式叫做高響應比優先調度算法。
響應比 = (等待時間 + 要求服務時間) / 要求服務時間 = 響應時間 / 要求服務時間
這種調度算法主要是為了解決 SJF 中長作業可能會餓死的問題,因為隨著等待時間的增長,響應比也會越來越高。
2.2 時間片輪轉
將所有就緒進程按 FCFS 的原則排成一個隊列,每次調度時,把 CPU 分配給隊首進程,該進程可以執行一個時間片。當時間片用完時,由計時器發出時鐘中斷,調度程序便停止該進程的執行,并將它送往就緒隊列的末尾,同時繼續把 CPU 分配給隊首的進程。
時間片輪轉算法的效率和時間片有很大關系。因為每次進程切換都要保存進程的信息并且載入新進程的信息,如果時間片太短,進程切換太頻繁,在進程切換上就會花過多時間。
2.3 多級反饋隊列
① 設置多個就緒隊列,并為各個隊列賦予不同的優先級。第一個隊列的優先級最高,第二個隊列次之,其余各隊列的優先權逐個降低。該算法賦予各個隊列中進程執行時間片的大小也各不相同,在優先權越高的隊列中,為每個進程所規定的執行時間片就越小。
② 當一個新進程進入內存后,首先將它放入第一隊列的末尾,按 FCFS 原則排隊等待調度。當輪到該進程執行時,如它能在該時間片內完成,便可準備撤離系統;如果它在一個時間片結束時尚未完成,調度程序便將該進程轉入下一個隊列的隊尾。
③ 僅當前 i -1 個隊列均空時,才會調度第 i 隊列中的進程運行。
優點:實時性好,也適合運行短作業和長作業。
2.4 短進程優先
3. 實時系統中的調度
實時系統要一個服務請求在一個確定時間內得到響應。
分為硬實時和軟實時,前者必須滿足絕對的截止時間,后者可以容忍一定的超時。
進程同步
1. 臨界區
對臨界資源進行訪問的那段代碼稱為臨界區。
為了互斥訪問臨界資源,每個進程在進入臨界區之前,需要先進行檢查。
// entry section // critical section; // exit section2. 同步與互斥
同步指多個進程按一定順序執行;互斥指多個進程在同一時刻只有一個進程能進入臨界區。
同步是在對臨界區互斥訪問的基礎上,通過其它機制來實現有序訪問的。
3. 信號量
**信號量(Samaphore)**是一個整型變量,可以對其執行 down 和 up 操作,也就是常見的 P 和 V 操作。
- down : 如果信號量大于 0 ,執行 - 1 操作;如果信號量等于 0,將進程睡眠,等待信號量大于 0;
- up:對信號量執行 + 1 操作,并且喚醒睡眠的進程,讓進程完成 down 操作。
down 和 up 操作需要被設計成原語,不可分割,通常的做法是在執行這些操作的時候屏蔽中斷。
如果信號量的取值只能為 0 或者 1,那么就成為了互斥量(Mutex),0 表示臨界區已經加鎖,1 表示臨界區解鎖。
typedef int samaphore; samaphore mutex = 1; void P1() {down(mutex);// 臨界區up(mutex); }void P2() {
down(mutex);
// 臨界區
up(mutex);
}
使用信號量實現生產者-消費者問題
使用一個互斥量 mutex 來對臨界資源進行訪問;empty 記錄空緩沖區的數量,full 記錄滿緩沖區的數量。
注意,必須先執行 down 操作再用互斥量對臨界區加鎖,否則會出現死鎖。如果都先對臨界區加鎖,然后再執行 down 操作,考慮這種情況:生產者對臨界區加鎖后,執行 down(empty) 操作,發現 empty = 0,此時生成者睡眠。消費者此時不能進入臨界區,因為生產者對臨界區加鎖了,也就無法對執行 up(empty) 操作,那么生產者和消費者就會一直等待下去。
#define N 100typedef int samaphore;
samaphore mutex = 1;
samaphore empty = N;
samaphore full = 0;
void producer() {
while(TRUE){
int item = produce_item;
down(empty);
down(mutex);
insert_item(item);
up(mutex);
up(full);
}
}
void consumer() {
while(TRUE){
down(full);
down(mutex);
int item = remove_item(item);
up(mutex);
up(empty);
consume_item(item);
}
}
4. 管程
使用信號量機制實現的生產者消費者問題需要客戶端代碼做很多控制,而管程把控制的代碼獨立出來,不僅不容易出錯,也使得客戶端代碼調用更容易。
c 語言不支持管程,下面的示例代碼使用了類 Pascal 語言來描述管程。示例代碼中的管程提供了 insert() 和 remove() 方法,客戶端代碼通過調用這兩個方法來解決生產者-消費者問題。
monitor ProducerConsumerinteger i;
condition c; procedure insert(); beginend;procedure remove(); beginend;
end monitor;
管程有一個重要特性:在一個時刻只能有一個進程使用管程。進程在無法繼續執行的時候不能一直占用管程,必須將進程阻塞,否者其它進程永遠不能使用管程。
管程引入了 條件變量 以及相關的操作:wait() 和 signal() 來實現同步操作。對條件變量執行 wait() 操作會導致調用進程阻塞,把管程讓出來讓另一個進程持有。signal() 操作用于喚醒被阻塞的進程。
使用管程實現生成者-消費者問題
monitor ProducerConsumercondition full, empty;
integer count := 0;
condition c; procedure insert(item: integer); beginif count = N then wait(full);insert_item(item);count := count + 1;if count = 1 ten signal(empty); end;function remove: integer; beginif count = 0 then wait(empty);remove = remove_item;count := count - 1;if count = N -1 then signal(full); end;
end monitor;
procedure producer
begin
while true do
begin
item = produce_item;
ProducerConsumer.insert(item);
end
end;
procedure consumer
begin
while true do
begin
item = ProducerConsumer.remove;
consume_item(item);
end
end;
進程通信
進程通信可以看成是不同進程間的線程通信,對于同一個進程內線程的通信方式,主要使用信號量、條件變量等同步機制。
1. 管道
管道是單向的、先進先出的、無結構的、固定大小的字節流,它把一個進程的標準輸出和另一個進程的標準輸入連接在一起。寫進程在管道的尾端寫入數據,讀進程在管道的首端讀出數據。數據讀出后將從管道中移走,其它讀進程都不能再讀到這些數據。
管道提供了簡單的流控制機制,進程試圖讀空管道時,在有數據寫入管道前,進程將一直阻塞。同樣地,管道已經滿時,進程再試圖寫管道,在其它進程從管道中移走數據之前,寫進程將一直阻塞。
Linux 中管道是通過空文件來實現。
管道有三種:
① 普通管道:有兩個限制:一是只支持半雙工通信方式,即只能單向傳輸;二是只能在父子進程之間使用;
② 流管道:去除第一個限制,支持雙向傳輸;
③ 命名管道:去除第二個限制,可以在不相關進程之間進行通信。
2. 信號量
信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其它進程也訪問該資源。因此,主要作為進程間以及同一進程內不同線程之間的同步手段。
3. 消息隊列
消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩沖區大小受限等缺點。
4. 信號
信號是一種比較復雜的通信方式,用于通知接收進程某個事件已經發生。
5. 共享內存
共享內存就是映射一段能被其它進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的 IPC 方式,它是針對其它進程間通信方式運行效率低而專門設計的。它往往與其它通信機制(如信號量)配合使用,來實現進程間的同步和通信。
6. 套接字
套接字也是一種進程間通信機制,與其它通信機制不同的是,它可用于不同機器間的進程通信。
經典同步問題
生產者和消費者問題前面已經討論過。
1. 讀者-寫者問題
允許多個進程同時對數據進行讀操作,但是不允許讀和寫以及寫和寫操作同時發生。
一個整型變量 count 記錄在對數據進行讀操作的進程數量,一個互斥量 count_mutex 用于對 count 加鎖,一個互斥量 data_mutex 用于對讀寫的數據加鎖。
typedef int semaphore;semaphore count_mutex = 1;
semaphore data_mutex = 1;
int count = 0;
void reader() {
while(TRUE) {
down(count_mutex);
count++;
if(count == 1) down(data_mutex); // 第一個讀者需要對數據進行加鎖,防止寫進程訪問
up(count_mutex);
read();
down(count_mutex);
count–;
if(count == 0) up(data_mutex);
up(count_mutex);
}
}
void writer() {
while(TRUE) {
down(data_mutex);
write();
up(data_mutex);
}
}
2. 哲學家進餐問題
五個哲學家圍著一張圓周,每個哲學家面前放著飯。哲學家的生活有兩種交替活動:吃飯以及思考。當一個哲學家吃飯時,需要先一根一根拿起左右兩邊的筷子。
下面是一種錯誤的解法,考慮到如果每個哲學家同時拿起左手邊的筷子,那么就無法拿起右手邊的筷子,造成死鎖。
#define N 5#define LEFT (i + N - 1) % N
#define RIGHT (i + N) % N
typedef int semaphore;
semaphore chopstick[N];
void philosopher(int i) {
while(TURE){
think();
down(chopstick[LEFT[i]]);
down(chopstick[RIGHT[i]]);
eat();
up(chopstick[RIGHT[i]]);
up(chopstick[LEFT[i]]);
}
}
為了防止死鎖的發生,可以加一點限制,只允許同時拿起左右兩邊的筷子,方法是引入一個互斥量,對拿起兩個筷子的那段代碼加鎖。
semaphore mutex = 1;void philosopher(int i) {
while(TURE){
think();
down(mutex);
down(chopstick[LEFT[i]]);
down(chopstick[RIGHT[i]]);
up(mutex);
eat();
down(mutex);
up(chopstick[RIGHT[i]]);
up(chopstick[LEFT[i]]);
up(mutex);
}
}
第三章 死鎖
死鎖的條件
死鎖的處理方法
1. 鴕鳥策略
把頭埋在沙子里,假裝根本沒發生問題。
這種策略不可取。
2. 死鎖預防
在程序運行之前預防發生死鎖。
2.1 破壞互斥條件
例如假脫機打印機技術允許若干個進程同時輸出,唯一真正請求物理打印機的進程是打印機守護進程。
2.2 破壞請求與保持條件
一種實現方式是規定所有進程在開始執行前請求所需要的全部資源。
2.3 破壞不可搶占條件
2.4 破壞環路等待
給資源統一編號,進程只能按編號順序來請求資源。
3. 死鎖避免
在程序運行時避免發生死鎖。
3.1 安全狀態
圖 a 的第二列 has 表示已擁有的資源數,第三列 max 表示總共需要的資源數,free 表示還有可以使用的資源數。從圖 a 開始出發,先讓 B 擁有所需的所有資源,運行結束后釋放 B,此時 free 變為 4;接著以同樣的方式運行 C 和 A,使得所有進程都能成功運行,因此可以稱圖 a 所示的狀態時安全的。
定義:如果沒有死鎖發生,并且即使所有進程突然請求對資源的最大需求,也仍然存在某種調度次序能夠使得每一個進程運行完畢,則稱該狀態是安全的。
3.2 單個資源的銀行家算法
一個小城鎮的銀行家,他向一群客戶分別承諾了一定的貸款額度,算法要做的是判斷對請求的滿足是否會進入不安全狀態,如果是,就拒絕請求;否則予以分配。
上圖 c 為不安全狀態,因此算法會拒絕之前的請求,從而避免進入圖 c 中的狀態。
3.3 多個資源的銀行家算法
上圖中有五個進程,四個資源。左邊的圖表示已經分配的資源,右邊的圖表示還需要分配的資源。最右邊的 E、P 以及 A 分別表示:總資源、已分配資源以及可用資源,注意這三個為向量,而不是具體數值,例如 A=(1020),表示 4 個資源分別還剩下 1/0/2/0。
檢查一個狀態是否安全的算法如下:
① 查找右邊的矩陣是否存在一行小于等于向量 A。如果不存在這樣的行,那么系統將會發生死鎖,狀態是不安全的。
② 假若找到這樣一行,將該進程標記為終止,并將其已分配資源加到 A 中。
③ 重復以上兩步,直到所有進程都標記為終止,則狀態時安全的。
4. 死鎖檢測與死鎖恢復
不試圖組織死鎖,而是當檢測到死鎖發生時,采取措施進行恢復。
4.1 死鎖檢測算法
死鎖檢測的基本思想是,如果一個進程所請求的資源能夠被滿足,那么就讓它執行,釋放它擁有的所有資源,然后讓其它能滿足條件的進程執行。
上圖中,有三個進程四個資源,每個數據代表的含義如下:
E 向量:資源總量A 向量:資源剩余量C 矩陣:每個進程所擁有的資源數量,每一行都代表一個進程擁有資源的數量R 矩陣:每個進程請求的資源數量
進程 P1 和 P2 所請求的資源都得不到滿足,只有進程 P3 可以,讓 P3 執行,之后釋放 P3 擁有的資源,此時 A = (2 2 2 0)。P1 可以執行,執行后釋放 P1 擁有的資源, A = (4 2 2 2) ,P2 也可以執行。所有進程都可以順利執行,沒有死鎖。
算法總結如下:
每個進程最開始時都不被標記,執行過程有可能被標記。當算法結束時,任何沒有被標記的進程都是死鎖進程。
① 尋找一個沒有標記的進程 Pi,它所請求的資源小于等于 A。② 如果找到了這樣一個進程,那么將 C 矩陣的第 i 行向量加到 A 中,標記該進程,并轉回 ①。③ 如果有沒有這樣一個進程,算法終止。
4.2 死鎖恢復
① 利用搶占恢復② 殺死進程
第四章 存儲器管理
虛擬內存
每個程序擁有自己的地址空間,這個地址空間被分割成多個塊,每一塊稱為一 頁。這些頁被映射到物理內存,但不需要映射到連續的物理內存,也不需要所有頁都必須在物理內存中。
當程序引用到一部分在物理內存中的地址空間時,由硬件立即執行必要的映射。當程序引用到一部分不在物理內存中的地址空間時,由操作系統負責將缺失的部分裝入物理內存并重新執行失敗的指令。
分頁與分段
1. 分頁
用戶程序的地址空間被劃分為若干固定大小的區域,稱為“頁”。相應地,內存空間分成若干個物理塊,頁和塊的大小相等。可將用戶程序的任一頁放在內存的任一塊中,實現了離散分配,由一個頁表來維護它們之間的映射關系。
2. 分段
上圖為一個編譯器在編譯過程中建立的多個表,有 4 個表是動態增長的,如果使用分頁系統的一維地址空間,動態遞增的特點會導致覆蓋問題的出現。
分段的做法是把每個表分成段,一個段構成一個獨立的地址空間。每個段的長度可以不同,可以動態改變。
每個段都需要程序員來劃分。
3. 段頁式
用分段方法來分配和管理虛擬存儲器。程序的地址空間按邏輯單位分成基本獨立的段,而每一段有自己的段名,再把每段分成固定大小的若干頁。
用分頁方法來分配和管理實存。即把整個主存分成與上述頁大小相等的存儲塊,可裝入作業的任何一頁。程序對內存的調入或調出是按頁進行的。但它又可按段實現共享和保護。
4. 分頁與分段區別
① 對程序員的透明性:分頁透明,但是分段需要程序員顯示劃分每個段。
② 地址空間的維度:分頁是一維地址空間,分段是二維的。
③ 大小是否可以改變:頁的大小不可變,段的大小可以動態改變。
④ 出現的原因:分頁主要用于實現虛擬內存,從而獲得更大的地址空間;分段主要是為了使程序和數據可以被劃分為邏輯上獨立的地址空間并且有助于共享和保護。
頁面置換算法
在程序運行過程中,若其所要訪問的頁面不在內存而需要把它們調入內存,但是內存已無空閑空間時,系統必須從內存中調出一個頁面到磁盤對換區中,并且將程序所需要的頁面調入內存中。頁面置換算法的主要目標是使頁面置換頻率最低(也可以說缺頁率最低)。
1. 最佳(Optimal)
所選擇的被換出的頁面將是最長時間內不再被訪問,通??梢员WC獲得最低的缺頁率。
是一種理論上的算法,因為無法知道一個頁面多長時間會被再訪問到。
舉例:一個系統為某進程分配了三個物理塊,并有如下頁面引用序列:
7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1
進程運行時,先將 7,0,1 三個頁面裝入內存。當進程要訪問頁面 2 時,產生缺頁中斷,會將頁面 7 換出,因為頁面 7 再次被訪問的時間最長。
2. 先進先出(FIFO)
所選擇換出的頁面是最先進入的頁面。
該算法會將那些經常被訪問的頁面也被換出,從而使缺頁率升高。
3. 最近最久未使用(LRU, Least Recently Used)
雖然無法知道將來要使用的頁面情況,但是可以知道過去使用頁面的情況。LRU 將最近最久未使用的頁面換出。
可以用棧來實現該算法,棧中存儲頁面的頁面號。當進程訪問一個頁面時,將該頁面的頁面號從棧移除,并將它壓入棧頂,這樣,最近被訪問的頁面的頁面號總是在棧頂,而最近最久未使用的頁面的頁面號總是在棧底。
4,7,0,7,1,0,1,2,1,2,6
4. 時鐘(Clock)
Clock 頁面置換算法需要用到一個訪問位,當一個頁面被訪問時,將訪問為置為 1。
首先,將內存中的所有頁面鏈接成一個循環隊列,當缺頁中斷發生時,檢查當前指針所指向頁面的訪問位,如果訪問位為 0,就將該頁面換出;否則將該頁的訪問位設置為 0,給該頁面第二次的機會,移動指針繼續檢查。
第五章 設備管理
磁盤調度算法
當多個進程同時請求訪問磁盤時,需要進行磁盤調度來控制對磁盤的訪問。磁盤調度的主要目標是使磁盤的平均尋道時間最少。
1. 先來先服務(FCFS, First Come First Serverd)
根據進程請求訪問磁盤的先后次序來進行調度。優點是公平和簡單,缺點也很明顯,因為未對尋道做任何優化,使平均尋道時間可能較長。
2. 最短尋道時間優先(SSTF, Shortest Seek Time First)
要求訪問的磁道與當前磁頭所在磁道距離最近的優先進行調度。這種算法并不能保證平均尋道時間最短,但是比 FCFS 好很多。
3. 掃描算法(SCAN)
SSTF 會出現進行饑餓現象??紤]以下情況,新進程請求訪問的磁道與磁頭所在磁道的距離總是比一個在等待的進程來的近,那么等待的進程會一直等待下去。
SCAN 算法在 SSTF 算法之上考慮了磁頭的移動方向,要求所請求訪問的磁道在磁頭當前移動方向上才能夠得到調度。因為考慮了移動方向,那么一個進程請求訪問的磁道一定會得到調度。
當一個磁頭自里向外移動時,移到最外側會改變移動方向為自外向里,這種移動的規律類似于電梯的運行,因此又常稱 SCAN 算法為電梯調度算法。
4. 循環掃描算法(CSCAN)
CSCAN 對 SCAN 進行了改動,要求磁頭始終沿著一個方向移動。
參考資料
Tanenbaum A S, Bos H. Modern operating systems[M]. Prentice Hall Press, 2014.
湯子瀛, 哲鳳屏, 湯小丹. 計算機操作系統[M]. 西安電子科技大學出版社, 2001.
Bryant, R. E., & O’Hallaron, D. R. (2004). 深入理解計算機系統.
小土刀的面試刷題筆記
進程間的幾種通信方式
總結
以上是生活随笔為你收集整理的操作系统学习总结(超赞!!!)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#中的修饰符及其说明
- 下一篇: 在windows环境下ftp服务器的文件