作業系統篇-程式管理

lovelife110發表於2020-10-11

以下針對java來說明

1. 程式 執行緒 纖程

在這裡插入圖片描述

程式和執行緒區別

程式就是一個程式執行起來的狀態,執行緒是一個程式中的不同的執行路徑。
程式是OS分配資源的基本單位,執行緒是執行排程的基本單位。分配資源最重要的是:獨立的記憶體空間,執行緒排程執行(執行緒共享程式的記憶體空間,沒有自己獨立的記憶體空間)

執行緒在Linux中的實現

《Linux核心設計與實現》第三版28頁
執行緒在Linux就是一個普通的程式,只不過和其他程式共享資源(記憶體空間,全域性資料等)

其他系統都有各自所謂的LWP的實現 Light Weight Process(輕量級程式)

纖程

在這裡插入圖片描述
即:使用者空間的執行緒

為什麼需要纖程:
java啟動執行緒,在作業系統級別,就是啟一個LWP。這是重量級執行緒。因為java啟動執行緒需要向作業系統申請資源,和作業系統核心打交道,需要系統呼叫。
而纖程是執行緒中的執行緒,對應圖最上面藍色框,在使用者空間,不需要向作業系統申請。
纖程處於執行緒內部,非常輕量級,可以線上程中快速切換。JVM自己管理,自己實現排程,自己切換,與作業系統無關。

纖程優勢:

  1. 佔有資源很少 OS : 執行緒:1M vs Fiber:4K
  2. 切換比較簡單
  3. 啟動很多個10W+

纖程的應用場景:
很短的計算任務,不需要和核心打交道,併發量高

2. 程式

Linux中也稱為task,是系統分配資源的基本單位
資源包括:獨立的地址空間,核心資料結構(程式描述符…),全域性變數, 資料段…
Linux程式描述符:PCB (Process Control Block),用於Linux的程式管理(執行緒有他的PCB)

殭屍程式

ps -ef |grep defunct (defunct表示無用的殭屍程式)

父程式產生子程式後,會維護子程式的PCB結構,子程式退出後,由父程式釋放,如果父程式沒有釋放,那麼子程式會成為一個殭屍程式(defunct)

孤兒程式

子程式結束之前,父程式已經退出,就會產生孤兒程式,孤兒程式會成為Init程式的子程式,由1號程式維護 (在圖形化Linux中是1457號執行緒)

排程策略

早期Linux 2.5 核心用的是Unix O(1)排程策略,按固定的時間片給程式

Linux核心2.6.23 採用CFS排程策略:Completely Fair Scheduler
按優先順序分配時間片的比例,記錄每個程式的執行時間,如果有一個程式執行時間不到他應該分配的比例,優先執行。 (比如有的程式開始沒做什麼就會讓出給其他程式,當開始需要做的時候,優先執行)

預設排程策略:
實時程式 > 普通程式
實時程式優先順序分高低 - FIFO (First In First Out),優先順序一樣的時候 - RR輪詢(Round Robin)
普通程式: CFS

其中等級最高的是FIFO,這種程式除非自己讓出CPU否則Linux會一直執行它,除非更高階的FIFO和RR搶佔它
RR只是這種這種程式中是同級別FIFO中的平均分配 ---- 比如FIFO中有兩個都是90優先順序的程式,這時候按照RR執行。
只有實時程式主動讓出,或者執行完畢後,普通程式才有機會執行。

3. 中斷

硬中斷

硬體和作業系統通訊的一種機制
在這裡插入圖片描述
執行過程:
鍵盤 -----中斷控制器(通知cpu一箇中斷訊號來了)--------cpu(在記憶體中固定位置找處理程式)-------執行程式(查中斷向量表,把中斷訊號給kernel)-------kernel(根據中斷訊號找程式)----------中斷處理程式(已經寫好的一堆處理程式,有處理鍵盤的,有處理印表機的)-----------------先由OS核心處理(上半場)------------再由應用程式處理(下半場)

軟中斷(80中斷)

中斷向量表特殊的符號
系統呼叫:int 0x80 (INT是用於x86處理器的彙編指令) 或者 sysenter原語(現在的cpu在硬體級別直接支援,彙編碼)

通過ax暫存器填入呼叫號(比如1代表exit函式,2代表fork函式)
引數是通過bx cx dx si di傳入核心
返回值通過ax返回

系統呼叫實現的hello world程式碼:

.section .data
msg:
        .ascii "Hello world!\n"
.section .text
.globl _start
_start:
        movl $4, %eax
        movl $1, %ebx
        movl $msg, %ecx
        movl $13, %edx
        int $0x80
        movl $1, %eax
        movl $0, %ebx
        int $0x80

系統呼叫是通過int 0x80來實現的,eax暫存器中為呼叫的功能號,ebx、ecx、edx、esi等等暫存器則依次為引數,從 /usr/include/asm/unistd.h中可以看到exit的功能號_NR_exit為1,write(_NR_write)功能號為4,因此第一個int 0x80呼叫之前eax暫存器值為4,ebx為檔案描述符,stdout的檔案描述符為1,ecx則為buffer的記憶體地址,edx為buffer長度。第二個int0x80之前eax為1表示呼叫exit,ebx為0表示傳入引數0。

注:eax 是32位的,ax是16位的

java中例子
java讀網路 – jvm read() – c庫read() - > 核心空間 -> system_call() (系統呼叫處理程式)-> sys_read()

相關文章