---
tags: OS
---
# OS concepts(keep updating)
- Explain lvalue and rvalue.
**Lvalue**: 就是一個運算式後還保留其狀態的一個物件 就是Lvalue; 也
就是說 所有的變數(variables)包含nonmodifiable, const 的變數都是Lvalue.
這邊一個重點是 const的變數也是Lvalue
**Rvalue**: 就是一個運算式過後其狀態就不會被保留了,
也就是一個暫存的數值
lvalue 可以 reference, rvalue 不能 reference。
- 什麼是OS?
確保 Process 可以正確執行,不會讓 Process 跟 Process 之間互相干擾,並透過 kernel mode 跟 user mode 保護硬體,並提供 high level 的 system call 讓使用者不能直接操作硬體,簡化操作,也更加有效率等。
- Program, Process and Thread?
Process 是 OS 分配 resource 的單位,相對的 Thread 是 OS 分配 CPU-time 的單位。
Process 之間的溝通相對複雜,要嘛是跟 OS 要一塊 Shared Memory,
不然就是透過 OS Message passing,
而 Thread 之間的溝通相對簡單,只要透過 Global Variable 即可,
雖然可能會有些問題(Race Condition)不過整體是比較簡單的,
再者 Thread 的切換可能不用轉到 Kernel Mode(看 Thread 如何實作)
又 Process 切換需要儲存許多資料到 PCB 而 Thread 相對少,
所以 Thread 的 Context Switch 也比 Process 快。
Program:放在二次儲存裝置中,尚沒有被Load到記憶體的一堆Code
稱之為「程式」。 (也就是還是死的)
Process:已經被Load到記憶體中,任何一行Code隨時會被CPU執行,且其宣告的在記憶體
的變數的值會隨著需求而不斷變動。
稱之為「程序」。 (也就是活的Program) => 恐龍本第三章
一個多工作業系統(Multitasking Operating System)可以同時運行多個Process
然而一個CPU一次只能做一件事情,但CPU的數量永遠少於運行中的Process數,
因此每個Process使用的時間需要被排程(Scheduling) => 恐龍本第五章
又每個Process間在記憶體中,如果擺放的方式不當,就會在記憶體中產生很多
沒辦法用到的碎片,因此MemoryManagement是一個問題 => 恐龍本第八章
另外,每個Process所需要的記憶體總合,也可能大於實體記憶體,因此需要另
外用二次儲存裝置充當虛擬記憶體(Virtual Memory),但是二次儲存裝置的速
度肯定很慢,因此如何做到對虛擬記憶體最小的依賴,盡量避免Page Fault(電
腦在主記憶體中找不到資料,而要去二次記憶體找,就稱為Page Fault)
防止Thrashing的發生(因為Virtual Memory演算法不當,造成幾乎每次存取都要
依賴二次記憶體,就是Thrashing),以達到效能最佳化,也是個學問 => 第九章
Thread :在同一個Process底下,有許多自己的分身,就是Thread,中文又翻成執行緒。
以往一個Process一次只能做一件事情,因此要一面輸入文字,一面計算字數,
這種事情是不可能的。但是有了Thread之後,可以在同一個Process底下,讓輸
入文字是一個Thread,計算文字又是另外一個Thread,對CPU來說兩個都是類似
一個Process,因此兩個可以同時做。
又一個Process底下有數個Thread,而一個Process的Global Variable可以讓
它的所有Thread共享,也就是所有Thread都可以存取同一個Process的Global
Variable。而每個Thread自己也有自己的專屬Variable。 => 恐龍本第四章
但是,如果有兩個Thread要存取同一個Global Variable,有可能發生問題,
也就是說可能會存取到錯的值(例如兩個Thread同時要對一個Variable做加減,
最後那個答案可能會是錯的),這就是Synchronization問題 =>恐龍本第六章
又,每一個Thread之間可能會互搶資源,而造成死結(Deadlock),只要以下四
個條件都滿足就有死結。(1)這個資源不能同時給兩個人用 (2)有一個人拿了一
個資源,又想拿別人的資源 (3)如果一個人占了茅坑不拉屎,占用資源很久,仍
不能趕他走 (4)A等B,B等C,C等D,D又等A 等成一圈。 要解決這種狀況有
Avoid(預防) 或 避免(Prevent)兩種方式,破除以上四種其中一種即可。
=> 恐龍本第七章
- 講解一下什麼是 (Pipeline) Hazard
分三種,Structural hazards, Data hazards, Control hazards。
**Structural hazards**
硬體資源不夠多而導致同一時間內要執行的多個指令無法執行,是先天限制。
如記憶體一次就只能給一個人讀取。
**Data hazards**
會發生在 lw 後面直接接 add 或是 branch 等,
在資料就緒之前就要使用,就會出現 Data hazards。
在連續數個指令都存取同一個暫存器時可能會發生的 Race Condition。
會造成 執行時 read/write 指令的順序與在組語之中的順序不同。
Data Hazard 又分為 RAW, WAW, WAR 三種,其中以 RAW 最為常見。
i1. R2 <- R1 + R3
i2. R4 <- R2 + R3
(R2 可能還沒寫入完全)
Hardware approach:forwarding,不用等到前一個instruction執行到最後一個stage,
在ALU算出result後就將它送入下個instruction中當作input。
Software approach:rearrange。
**Control hazards**
當我們需要某個指令的結果來作一些決定,可是這個指令還在執行,無法馬上提供所需要的結果。
發生在會修改 Program Counter 的指令(Jump/Branch/else)
(a)stall:如果知道是一個branch instruction,則暫停直到正確的condition知道後才開始下一個instruction。
(b)predict:事先預測branch instruction不會發生,如果預測結果錯誤則放棄已經進入pipeline的指令而fetch branch target的instruction進入pipeline,如果預測成功就可以快速順利的運作下去。
(c)delayed branch:在branch instruction之後先執行下個合適的指令,但是必須確保這個指令是安全指令,不會影響program的執行結果才行。
- Interrupt 的種類
- External Interrupt(外部中斷): CPU 外的週邊元件所引起的。
(I/O Complete Interrupt, I/O Device error)
- Internal Interrupt(內部中斷):不合法的用法所引起的。
(Debug、Divide-by-zero、overflow)
- Software Interrupt(軟體中斷):使用者程式在執行時,若需要OS 提供服
務時,會藉由System Call 來呼叫OS 執行對應的service routine,完成服務請求
後,再將結果傳回給使用者程式。
● Interrupt 的處理流程

Setps
1. 暫停目前process 之執行。
2. 保存此process 當時執行狀況。
3. OS 會根據Interrupt ID 查尋Interrupt vector。
4. 取得ISR(Interrupt Service Routine)的起始位址。
5. ISR 執行。
6. ISR 執行完成,回到原先中斷前的執行。
- ISR:
ISR簡單來說就是中斷會跳去執行的函式,而他跟task或process不同的地方是,
做context switch的時候ISR只會PUSH部份暫存器,而 task 或 process 會 push 所有的暫存器
- System Call
System call 是 process 與作業系統之間的介面。
System call 是由 Linux kernel 所實作並提供給使用者,
user-space program 可透過 system call 與Linux kernel 溝通
作為user program執行時與OS之間的溝通介面,當user program需要OS提供服務時,
藉由呼叫system call(伴隨trap to monitor mode)通知OS,
OS可依據system call ID查表,啟動service routine執行,
得到結果,再傳回給user program,完成服務請求
System Call種類:
Process Control
File Management
Device Management
Information Maintenance
Communication
- Real-time operating system, RTOS
實時作業系統與一般的作業系統相比,最大的特色就是其「實時性」,
也就是說,如果有一個任務需要執行,
實時作業系統會馬上(在較短時間內)執行該任務,
不會有較長的延時。這種特性保證了各個任務的及時執行
設計實時作業系統的首要目標不是高的吞吐量,而是保證任務在特定時間內完成
- Memory Hierarchy
Register – Cache – Main Memory – Disk –Tape
愈快 ← 速度 → 愈慢
愈昂貴 ← 價格 → 愈便宜
愈小 ← 容量 → 愈大
**SRAM** (Static RAM):用Flip/Flop儲存,速度快,密度低(元件大),成本高,作Cache等快速記憶體,不須Refresh。
**DRAM** (Dynamic RAM):用電容器製作,速度慢,密度高(元件小),成本低,為Main Memory的主體,須Refresh
儲存的電荷會隨著時間漸漸消失,因此需要有個再充電(Refresh)的動作保持電容儲存的資料
- User space/ Kernel space
簡單說,Kernel space 是 Linux 內核的運行空間,User space 是用戶程序的運行空間。
為了安全,它們是隔離的,即使User的程序崩潰了,內核也不受影響。
Kernel space 可以執行任意命令,調用系統的一切資源;
User space 只能執行簡單的運算,不能直接調用系統資源,必須通過系統接口(又稱 system call),才能向內核發出指令。
- DMA是什麼,好處是?請簡單在白板上畫出他的架構圖。

直接記憶體存取(Direct Memory Access,DMA)
是電腦科學中的一種記憶體存取技術。
它允許某些電腦內部的硬體子系統(電腦外設),
可以獨立地直接讀寫系統記憶體,而不需中央處理器(CPU)介入處理 。
在同等程度的處理器負擔下,DMA是一種快速的資料傳送方式。
很多硬體的系統會使用DMA,包含硬碟控制器、繪圖顯示卡、網路卡和音效卡。
DMA是所有現代電腦的重要特色,它允許不同速度的硬體裝置來溝通,
而不需要依於中央處理器的大量中斷負載。
否則,中央處理器需要從來源把每一片段的資料複製到暫存器,
然後把它們再次寫回到新的地方。
在這個時間中,中央處理器對於其他的工作來說就無法使用。
- CPU架構

中央處理單元(CPU)主要由運算器、控制器、寄存器三部分組成,
從字面意思看運算器就是起著運算的作用,
控制器就是負責發出CPU每條指令所需要的信息,
寄存器就是保存運算或者指令的一些臨時文件,這樣可以保證更高的速度。
- Control Unit
CPU 可以說是電腦的大腦,而 Control Unit 則可以說是CPU的艦長,負責發號司令負責叫ALU運算跟控制暫存器
- Arithmetic Logic Unit(ALU)
負責實際運算的部份,Input 由 Control Unit 控制,運算完的結果透過 Output 或是 Flags 來讓 Control Unit 知道結果
Register
- Register(暫存器)在 CPU 裡面扮演重要的腳色,它們讓 ALU 計算出來的數值可以有地方暫時存放,以供之後的運算。而Control unit 會用set wire跟enable wire來控制那些 Register 會被寫入,和輸出: - set wire: 讓 ALU 計算完的值可以透過 bus(匯流排)來寫入 register - enable wire: 讓register的值可以輸出到 bus 上
其它的Register
Instruction register: 把指令的種類輸出到 Control Unit
Instruction address register: 下一個指令所在的 address 輸出到 memory address register
Memory address register: 把 address 輸出到 Memory
因為多個 Register 彼此共用一個 bus,為了要讓 ALU 可以讀到兩個Input,會在其中一個Input 加入一個 Temp register,讓這個 register 可以暫時鎖死一個值到 ALU,然後另一個值再從Register中用 enable wire直接打到 ALU上
Intel和ARM處理器的第一個區別是,前者使用複雜指令集(CISC),而後者使用精簡指令集(RISC)
開始的處理器都是CISC架構,為了減少程式設計師的設計時間,逐漸開發出單一指令,複雜操作的程式碼,設計師只需寫下簡單的指令,再交由CPU去執行。但是後來有人發現,整個指令集中,只有約20%的指令常常會被使用到,約佔整個程式的80%;剩餘80%的指令,只佔整個程式的20%。
RISC的優點列舉如下:
指令長度固定,方便CPU解碼,簡化解碼器設計。
盡量在CPU的暫存器(最快的記憶體元件)裡操作,避免額外的讀取與載入時間。
由於指令長度固定,更能受益於執行線路管線化(pipeline)後所帶來的效能提升。
處理器簡化,電晶體數量少,易於提升運作時脈。比起同時脈的CISC處理器,耗電量較低。
RISC的缺點列舉如下:
複雜指令需要由許多的小指令去完成,程式變得比較大,記憶體也占用比較多,這在硬碟昂貴,常常使用磁帶儲存的時代來說,是個大缺點。
程式變長,代表著讀取工作變得繁重,需要更多的時間將指令從記憶體載入至處理器內。
- write through / write back 的差別,哪個快?
write through: 是直接把資料寫回記憶體
write back: 是先將資料按一定數量接受下來﹐然後將相同位址的資料一次過整批送回記憶體(batch?)
write back快很多,早期的 cache 只有 write through 模式﹐但現在的 cache 都使用 write back 模式
- Cache coherence
在計算機科學中,快取一致性(英語:Cache coherence,或cache coherency),又譯為快取連貫性、快取同調,是指保留在快取記憶體中的共享資源,保持資料一致性的機制。
在一個系統中,當許多不同的裝置共享一個共同記憶體資源,在快取記憶體中的資料不一致,就會產生問題。這個問題在有數個CPU的多處理機系統中特別容易出現。
快取一致性可以分為三個層級:
1. 在進行每個寫入運算時都立刻採取措施保證資料一致性
2. 每個獨立的運算,假如它造成資料值的改變,所有行程都可以看到一致的改變結果
3. 在每次運算之後,不同的行程可能會看到不同的值(這也就是沒有一致性的行為)
Directory-based Protocol
首先要來了解一下這個 protocol 用三種狀態來描述Data的狀況
分別用U,S,E 這三個代號來簡稱
**Uncached** :data 的狀態目前是閒置的 (沒有正在被share) 所以可以放心拿去用
**Shared**:data 的狀態目前是被shared,也就是有其他的CPU把data copy去他的cache裡面使用,此時還是可以把data拿去用!只是要登記一下你也有在用就是了
**Exclusive**:這是mutual exclusive的意思,表示現在data的狀態正在被修改中,其他人不可以使用!有再用的人請把手邊那份的先丟掉,因為data要被更新了!
快取一致性的問題
這裡用 snooping 維持一致性
採用 wrirte-invalidate 和 write back
write-invalidate簡單說是write miss時
他會送出無效訊號把其它拷貝毒死再更新自己的資料
每個processor會有一個snoop tag打聽 bus 上的資訊
而快取區塊會有三種狀態 shared, exclusive, invalid
當read miss、write miss狀態就會轉換
而read hit不會。
以下(1)~(6)為題目的路徑標示
(1)invalid→shared
當此無效區塊發生read miss,則直接把要讀的block搬上來變shared
(2)shared→shared
當此共享區塊發生read miss,因為本來區塊就是乾淨的所以還是可以共享
(3)shared→exclusive
當此共享區塊發生write miss,則送出Invalidate訊息把所有copy殺掉
再讀要的區塊並寫入,改成exclusive
(4)exclusive→shared
當此互斥區塊發生read miss,因為髒髒被寫過而且別人沒有此區塊資料所以
要write back回memory再變成shared
(5)exclusive→exclusive
當此互斥區塊發生write miss,一樣要先write-back回memory但他還是髒的。
(6)invalid→exclusive
當此無效區塊發生write miss,則讀取所需區塊並寫入,然後改成互斥狀態。
- cache line
cache 存取資料時,通常是分成很多小單位,稱為 cache line。
例如,Pentium III 的 cache line 長度是 32 bytes。
也就是說,如果 CPU 要讀取記憶體位址 0x00123456 的一個 32 bits word(即 4 bytes),且 cache 中沒有這個資料,則 cache 會將 0x00123440 ~ 0x0012345F 之間的 32 bytes 資料(即一整個 cache line 長度)都讀入 cache 中。
所以,當 CPU 讀取連續的記憶體位址時,資料都已經讀到 cache 中了。
- 什麼情況下會產生 stack overflow,如何避免
程式在使用記憶體時,因為 call stack 堆太高了(Deep Recursive Function)不小心把記憶體用完,所產生的 overflow
避免 :
1. 檢查遞迴的終止條件
2. 把遞迴攤平成迴圈
- Interrupt,寫 ISR要注意什麼
1. ISR不能有返回值;
2. ISR不能傳遞參數;
3. ISR應該是短而高效的,在ISR中做浮點運算是不明智的;
4. ISR中不應該有重入和性能上的問題,因此不應該使用pintf()函數。
- atomic
atomic transaction
因為一個 transaction 由一 instruction set 所組成
如果指明了某一 transaction 是 atomic
代表這個 transaction 在執行時, 其所屬的 instruction set 不是全部執行
不然就是全部不執行, 沒有那種執行一半的
- Interrupt Edge trigger 和 level trigger 的差別
- Level-triggered
意指事件監看端 (作業系統/Kernel) 在每一次察覺到有新事件時, 都會通知事件接收端 (軟體程式).
- Edge-triggered
則指事件監看端 (作業系統/Kernel) 在察覺到有新事件時, 會依照事件接收端 (軟體程式) 的處理狀態 (state) 來決定是否需要通知. 大致流程為:
1. 接收端處理狀態初始為 low
2. 事件發生
3. 監看端得知接收端狀態為 low, 遂通知接收端並且設定處理狀態為 high
4. 該狀態會一直保持為 high 直到接收端將所有事件都處理完才會重置回 low, 而期間就算有新事件發生, 監看端也不會發出通知
舉一個生動一點的例子: 國王屬咐太監,如果有大臣來覲見就把它領來書房。這個例子中,國王即為事件接收端、太監則為事件監看端,而大臣的來訪即為事件。如果這個太監是按 Level-triggered 來行事,那麼每來一位大臣他就要領去書房一次。反之若太監以 Edge-triggered 來行事,當領了一位大臣去書房後,他就知道國王是「已經知道有大臣來訪」的狀態 (處理狀態為 high),後續再有大臣來,就會直接放行請大臣自己進去、不再通知國王。直到國王再主動跟太監說「我都謁見完了」(處理狀態重置為 low),之後太監再看到有大臣來訪才會再行通知。
- static 的作用
Refer to [static](https://shengyu7697.github.io/cpp-static/)
1. 限制變數的作用區域 (****放在全域變數/函數之前,****)
其他檔案 extern 這個變數時會出現編譯錯誤
1. 使得變數生命週期跟函數一樣長 (****放在區域變數之前****)
```cpp
// g++ cpp-static1.cpp -o a.out
#include <iostream>
using namespace std;
void count() {
static int counter = 0;
counter++;
cout << "counter = " << counter << endl;
}
int main() {
count();
count();
count();
return 0;
}
```
```jsx
counter = 1
counter = 2
counter = 3
```
- h頭文件中的ifndef/define/endif 的作用?
防止header 被重複引用
- #include<file.h> 與 #include "file.h"的區别?
一個從 standard lib 取得, 一個從當前路徑搜尋與引用
- 記憶體配置 example
Refer to [C 語言程式記憶體配置](https://blog.gtwang.org/programming/memory-layout-of-c-program/)
```c
#include <stdio.h>
#include <stdlib.h>
const int global_x = 1; // 儲存於 data 區段(唯讀區域)
int global_y = 1; // 儲存於 data 區段(可讀寫區域)
int global_z; // 儲存於 bss 區段 (未初始化全域變數)
int main() {
const static int x = 1; // 儲存於 data 區段(唯讀區域)
static int y = 1; // 儲存於 data 區段(可讀寫區域)
static int z; // 儲存於 bss 區段
int w = 1; // 儲存於 stack 區段
// 儲存於 heap 區段
char *buf = (char*) malloc(sizeof(char) * 100);
// ...
free(buf);
return 0;
}
```
- 平衡二元樹
左右子樹深度差不大於1
- 關鍵字 const 含意?
```c
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
```
- 1 and 2 常整數
- 3 指針可改 指的整數不可改
- 4 指針不可改 指的整數可改
- 5 皆不可改
用意 : 可產生更緊湊的代碼, 傳達給閱讀代碼的人一些訊息, 保護不希望被改變的變數
- 關鍵字volatile有什麼含意 給出三個不同的例子
1. 並型設備的硬件寄存器(如:狀態寄存器)
2. 一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables 全局變量,靜態變量)
3. 多線程應用中被幾個任務共享的變量
- pipeline, 用pipeline有什麼好處/壞處?
是為了讓計算機和其它數位電子裝置能夠加速指令的通過速度(單位時間內被執行的指令數量)而設計的技術。
IF → ID → EX → MEM → WB
IF(Instruction Fetch) 和 ID(Instruction Decode) stage
CPU會先提取(Fetch)指令,先到這個要執行指令的address,去將該指令從memory提取到CPU,再進行Decode(解碼),根據這道指令0和1的組成去判斷這道指令的內容,舉個比較簡單的例子就是加、減 、 乘 、 除指令這四道指令在機器碼的某一個部分會不同,CPU就可以透過那一部分去判斷這道指令的目的。
EX(Execution) MEM(Memory access)
接下來當CPU知道這道指令的內容之後,就要執行相對應的運算,這裡由算術邏輯單元(ALU),根據這道指令的目的、輸入去計算出結果,需要計算的不只是有運算指令,還包含了load store指令,因為要計算出memory的address,才能夠去進行訪問(Access)對memory進行讀寫,在memory讀寫的部分就是由MEM stage進行,在這裡向ram或是cache及外部的memory進行access並讀寫,將CPU register資料寫出去或者是將資料讀到register內,因為在RISC的CPU架構中都是以 load store machine為主,並不能夠直接對memory進行運算,所有運算的資料都必須在register內才能執行,因此如果要計算memory的資料,需要將資料從memory讀到register運算完後再從register寫回memory。
WB(Write-Back)
這裡代表著一道指令的完成,如果是計算指令會將運算後的結果寫回 destination register
沒pipeline的架構產生的效率低,因為有些CPU的模組在其他模組執行時是閒置的。
如果一條pipeline能夠在每一個cpu clock週期接納一條新的指令,
被稱為完整管線化(fully pipelined)。
因pipeline中的指令需要延遲處理而要等待數個cpu clock,被稱為非完整管線化。
在執行相同的指令時,非pipeline的指令傳輸延遲時間(The instruction latency)比pipeline處理器明顯較短。
這是因為pipeline的處理器必須在資料路徑(data path)中添加額外正反器(flip-flops)
- deadlock introduction
Refer to [Deadlock](https://www.mropengate.com/2015/01/operating-system-ch7-deadlock.html)
Deadlock 發生須符合以下四項充要條件 :
1. Mutual exclusion:某些資源在同一個時間點最多只能被一個 process 使用
2. Hold and wait:某 process 持有部分資源,並等待其他 process 正在持有的資源
3. No preemption:process 不可以任意強奪其他 process 所持有的資源
4. Circular waiting:系統中存在一組 processes P=P0,P1,…,Pn,其中 P0 等待 P1 所持有的資源 ... Pn 等待 P0 所持有的資源,形成循環式等待。(因此,deadlock不會存在於single process環境中)
Deadlock 三種處理方法:
1. Deadlock prevention
2. Deadlock avoidance
3. Deadlock detection & recovery
prevention 和 avoidance 保證系統不會進入 Deadlock,但資源利用度低;而 detection 資源利用度較高,但若 Deadlock 需要做 recovery,則 cost 極高。
**Deadlock prevention**
打破必要條件四項之一,即可保證 Deadlock 永不發生。
打破 Mutual exclusion:為資源與生俱來之性質,無法打破。
打破 Hold and wait:系統產能低。
除非 proces 可以一次取得所有工作所需的資源,才允許持有資源。
process 執行之初可持有部分資源,但要再申請資源前,要先釋放手中所有資源。
打破 Preemption : 讓高優先 process 搶低優先 process 的資源,會造成 starvation。
打破 Circular waiting:Process須按照資源編號遞增方式申請資源。
**Deadlock avoidance**
當 process 提出資源申請時,OS 會執行Banker algorithm 來判斷系統在「假設核准該申請後」是否處於 Safe state,是則核准,否則請 process 等待。
safe state : 存在 safe sequence
unsafe state : 可能有 deadlock
**Deadlock Detection**
Allow system to enter deadlock state.
Detection algorithm :
Single instance : topological sort (using wait-for graph)
使用 adjcent matrix : O(n2)
使用 adjcent list : O(V+E)
Several instance : 用 Banker algorithm 判斷系統是否已經在 unsafe state
Recovery scheme :
終止 process (成本都高)
全部刪除
一次刪一個 process,直到打破 deadlock。
資源搶奪
剝奪 victim process 資源 (可能造成 starvation)
恢復無該資源前狀態 (cost 高)
- 阻塞 (Blocking) 與非阻塞 (Non-Blocking)
阻塞 (Blocking) 與非阻塞 (Non-Blocking) 描述的是 請求 在等待結果時的 狀態。
1. 阻塞 (Blocking):調用的程序或者應用程式發起請求,在獲得結果之前,調用方的程序會懸 (Hang) 住不動,無法回應,直到獲得結果。
2. 非阻塞 (Non-Blocking):概念與阻塞相同,但是調用方不會因為等待結果,而懸著不動。後續通常透過輪詢機制 (Polling) 機制取得結果。
- 同步 (Synchronous) 與 非同步 (Asynchronous)
同步 (Synchronous) 與 非同步 (Asynchronous) 描述的是:使用者執行緒與 Kernel 的 通訊模式。
1. 同步 (Synchronous):使用者執行緒發出 I/O 請求後,要等待、或者輪詢 Kernel I/O 的操作完成後,才能繼續執行。
等待 Kernel 回覆:Blocking IO,縮寫成 BIO
輪詢類似於 Non-Blocking IO,縮寫成 NIO
2. 非同步 (Asynchronous):或稱 異步,使用者執行緒發出 I/O 請求後仍然繼續執行下一個操作,當 Kernel I/O 操作結束後,會通知執行緒,或者呼叫 callback 函數。
同步 中文的意思很容易誤解為,很多事同時做,實際上是事情有 先後關係 的概念,也就是 有序性 (oredered);而 非同步 才是類似於很多事情在同一個時間一起發動,他是 無序性 (non-ordered)。
- spinlock & mutex & semaphore 的作用和區別
Refer to [spinlock & mutex & semaphore 的作用和區別](https://welkinchen.pixnet.net/blog/post/47071066-spinlock-%26-mutex-%26-semaphore-%E7%9A%84%E4%BD%9C%E7%94%A8%E5%92%8C%E5%8D%80%E5%88%A5)
- Critical section
process (程序) 、或執行緒 可能有部分程式 , 只能允許一人進入 。這段程式 稱為 臨界區段(Critical section) 簡稱 cs 。
不是臨界區段(Critical section) 的程式 ,稱為 剩餘區(remainder section) 簡稱rs
有critical section 的 執行緒 ,能滿足這三個東西
1. mutual exclusion: 若執行緒在執行「critical section」,
其它執行緒都不該進入它們的「critical section」。
(並不是其它執行緒不能進入CPU哦,只是其他執行緒 在 cs外面 無窮迴圈)
2. progress: 不想進入 critical section 的執行緒 不可以阻礙其它 執行緒 進入 critical section,
即不可參與進入 critical section 的決策過程。
3. bounded waiting: 若一個執行緒想執行CS,等待的執行緒數量必須是有限的,不能無限被插隊 。即若有 n 個 執行緒,則任一 執行緒 至多等待 n-1 次(n-1個執行緒)即可進入,隱含 No starvation (沒有人餓肚子,每個執行緒都要吃東西)。
- Process Scheduling
Refer to [Process Scheduling](https://hackmd.io/@Chang-Chia-Chi/OS-CH5)
- Context Switching
CPU在執行時,只能運用一個process,如果切換給另一個Process時,須將舊Process的相關資訊 (e.g.PCB內容) 儲存起來,並載入新Process的相關資訊,此過程稱『Context Switching』。
- 封裝、繼承、多型
封裝、繼承、多型為物件導向三大基礎 。
此三者具有次序性 , 沒有封裝就不可能有繼承 、沒有繼承就不可能有多型。
封裝 (Encapsulation) 的目的
是將 Class 裡的屬性用 private 隱藏,
只能透過public的方法存取資料。
(隱藏程式細節,避免直接處理造成的困擾。使開發與維護更容易)
拿現實世界來舉例的話
自動販賣機來說好了,有投錢的裝置,選擇商品的按鈕,拿取商品的箱子
買可樂的步驟投錢,選可樂,拿可樂
你不用知道為何投錢後按鈕燈會亮,按按鈕後可樂如何掉下來
這些知識都被封裝起來了
繼承 (Inheritance) 的目的,是
要達到「程式碼再用」(Code Reuse) 或「介面再用」。
透過繼承,可以適當的切割類別,
並在衍生類別中重複使用、擴充和修改基底類別中定義的行為,
又不破壞原先基底類別設計。
多型 (Polymorphism) 指的是不同型態的物件,
定義相同的操作介面,由於被呼叫者 (Caller)有著相同的介面,
呼叫者並不用指定特別型別,只需針對介面進行操作,
實際執行的物件則在runtime決定,藉此增加程式碼的彈性。
class Drink{}
class Cola entends Drink{}
class Juice entends Drinks{}
Drink mydrinks[] = [ new Cola(), new Juice() ]
- reference v.s. pointer
- 引用需初始化 指針不用
- 引用初始化後值不可改變 指針可以改變
- 引用值不為空