動態分區分配算法有哪幾種?
本期是操作系統開胃菜,既然是開胃菜那字數少一點好了哈哈,就先來21 道題,16213 個字好了。
還有本來想等到《逆襲進大廠》系列出完之后再放出 PDF 的,可很多人讓我先出個第一版先看著…..
一開始我是拒絕的,可真的太多人跟我說了,考慮到最近金三銀四以及春招找工作期間很多人都需要這份資料,emm…
沒辦法,先出第一期好了。
以下是本期目錄,看看你會多少。

閑話少敘,開車開車!

1、進程、線程和協程的區別和聯系

1、進程是資源調度的基本單位,運行一個可執行程序會創建一個或多個進程,進程就是運行起來的可執行程序
2、線程是程序執行的基本單位,是輕量級的進程。每個進程中都有唯一的主線程,且只能有一個,主線程和進程是相互依存的關系,主線程結束進程也會結束。多提一句:協程是用戶態的輕量級線程,線程內部調度的基本單位
2、線程與進程的比較
1、線程啟動速度快,輕量級
2、線程的系統開銷小
3、線程使用有一定難度,需要處理數據一致性問題
4、同一線程共享的有堆、全局變量、靜態變量、指針,引用、文件等,而獨自占有棧
3、一個進程可以創建多少線程,和什么有關?
理論上,一個進程可用虛擬空間是2G,默認情況下,線程的棧的大小是1MB,所以理論上最多只能創建2048個線程。如果要創建多于2048的話,必須修改編譯器的設置。
因此,一個進程可以創建的線程數由可用虛擬空間和線程的棧的大小共同決定,只要虛擬空間足夠,那么新線程的建立就會成功。如果需要創建超過2K以上的線程,減小你線程棧的大小就可以實現了,雖然在一般情況下,你不需要那么多的線程。過多的線程將會導致大量的時間浪費在線程切換上,給程序運行效率帶來負面影響。
4、外中斷和異常有什么區別?
外中斷是指由 CPU 執行指令以外的事件引起,如 I/O 完成中斷,表示設備輸入/輸出處理已經完成,處理器能夠發送下一個輸入/輸出請求。此外還有時鐘中斷、控制臺中斷等。
而異常時由 CPU 執行指令的內部事件引起,如非法操作碼、地址越界、算術溢出等。
5、進程線程模型你知道多少?
對于進程和線程的理解和把握可以說基本奠定了對系統的認知和把控能力。其核心意義絕不僅僅是“線程是調度的基本單位,進程是資源分配的基本單位”這么簡單。
多線程
我們這里討論的是用戶態的多線程模型,同一個進程內部有多個線程,所有的線程共享同一個進程的內存空間,進程中定義的全局變量會被所有的線程共享,比如有全局變量int i = 10,這一進程中所有并發運行的線程都可以讀取和修改這個i的值,而多個線程被CPU調度的順序又是不可控的,所以對臨界資源的訪問尤其需要注意安全。
我們必須知道,做一次簡單的i = i + 1在計算機中并不是原子操作,涉及內存取數,計算和寫入內存幾個環節,而線程的切換有可能發生在上述任何一個環節中間,所以不同的操作順序很有可能帶來意想不到的結果。
但是,雖然線程在安全性方面會引入許多新挑戰,但是線程帶來的好處也是有目共睹的。首先,原先順序執行的程序(暫時不考慮多進程)可以被拆分成幾個獨立的邏輯流,這些邏輯流可以獨立完成一些任務(最好這些任務是不相關的)。
比如 QQ 可以一個線程處理聊天一個線程處理上傳文件,兩個線程互不干涉,在用戶看來是同步在執行兩個任務,試想如果線性完成這個任務的話,在數據傳輸完成之前用戶聊天被一直阻塞會是多么尷尬的情況。
對于線程,我認為弄清以下兩點非常重要:
線程之間有無先后訪問順序(線程依賴關系)
多個線程共享訪問同一變量(同步互斥問題)
另外,我們通常只會去說同一進程的多個線程共享進程的資源,但是每個線程特有的部分卻很少提及,除了標識線程的tid,每個線程還有自己獨立的棧空間,線程彼此之間是無法訪問其他線程棧上內容的。
而作為處理機調度的最小單位,線程調度只需要保存線程棧、寄存器數據和PC即可,相比進程切換開銷要小很多。
線程相關接口不少,主要需要了解各個參數意義和返回值意義。
線程創建和結束
背景知識:
在一個文件內的多個函數通常都是按照main函數中出現的順序來執行,但是在分時系統下,我們可以讓每個函數都作為一個邏輯流并發執行,最簡單的方式就是采用多線程策略。在main函數中調用多線程接口創建線程,每個線程對應特定的函數(操作),這樣就可以不按照main函數中各個函數出現的順序來執行,避免了忙等的情況。線程基本操作的接口如下。
相關接口:
創建線程:int pthread_create(pthread_t *pthread, const pthread_attr_t *attr, void (start_routine)(void *), void *agr);
創建一個新線程,pthread和start_routine不可或缺,分別用于標識線程和執行體入口,其他可以填NULL。
pthread:用來返回線程的tid,*pthread值即為tid,類型pthread_t == unsigned long int。
attr:指向線程屬性結構體的指針,用于改變所創線程的屬性,填NULL使用默認值。
start_routine:線程執行函數的首地址,傳入函數指針。
arg:通過地址傳遞來傳遞函數參數,這里是無符號類型指針,可以傳任意類型變量的地址,在被傳入函數中先強制類型轉換成所需類型即可。
獲得線程ID:pthread_t pthread_self();
調用時,會打印線程ID。
等待線程結束:int pthread_join(pthread_t tid, void** retval);
主線程調用,等待子線程退出并回收其資源,類似于進程中wait/waitpid回收僵尸進程,調用pthread_join的線程會被阻塞。
tid:創建線程時通過指針得到tid值。
retval:指向返回值的指針。
結束線程:pthread_exit(void *retval);
子線程執行,用來結束當前線程并通過retval傳遞返回值,該返回值可通過pthread_join獲得。
retval:同上。
分離線程:int pthread_detach(pthread_t tid);
主線程、子線程均可調用。主線程中pthread_detach(tid),子線程中pthread_detach(pthread_self()),調用后和主線程分離,子線程結束時自己立即回收資源。
tid:同上。
線程屬性值修改
背景知識:
線程屬性對象類型為pthread_attr_t,結構體定義如下:
typedef struct{
int etachstate; // 線程分離的狀態
int schedpolicy; // 線程調度策略
struct sched_param schedparam; // 線程的調度參數
int inheritsched; // 線程的繼承性
int scope; // 線程的作用域
// 以下為線程棧的設置
size_t guardsize; // 線程棧末尾警戒緩沖大小
int stackaddr_set; // 線程的棧設置
void * stackaddr; // 線程棧的位置
size_t stacksize; // 線程棧大小
}pthread_arrt_t;
相關接口:
對上述結構體中各參數大多有:pthread_attr_get()和pthread_attr_set()系統調用函數來設置和獲取。這里不一一羅列。
多進程
每一個進程是資源分配的基本單位。
進程結構由以下幾個部分組成:代碼段、堆棧段、數據段。代碼段是靜態的二進制代碼,多個程序可以共享。
實際上在父進程創建子進程之后,父、子進程除了pid外,幾乎所有的部分幾乎一樣。
父、子進程共享全部數據,但并不是說他們就是對同一塊數據進行操作,子進程在讀寫數據時會通過寫時復制機制將公共的數據重新拷貝一份,之后在拷貝出的數據上進行操作。
如果子進程想要運行自己的代碼段,還可以通過調用execv()函數重新加載新的代碼段,之后就和父進程獨立開了。
我們在shell中執行程序就是通過shell進程先fork()一個子進程再通過execv()重新加載新的代碼段的過程。
進程創建與結束
背景知識:
進程有兩種創建方式,一種是操作系統創建的一種是父進程創建的。從計算機啟動到終端執行程序的過程為:0號進程 -> 1號內核進程 -> 1號用戶進程(init進程) -> getty進程 -> shell進程 -> 命令行執行進程。所以我們在命令行中通過 ./program執行可執行文件時,所有創建的進程都是shell進程的子進程,這也就是為什么shell一關閉,在shell中執行的進程都自動被關閉的原因。從shell進程到創建其他子進程需要通過以下接口。
相關接口:
創建進程:pid_t fork(void);
返回值:出錯返回-1;父進程中返回pid > 0;子進程中pid == 0
結束進程:void exit(int status);
status是退出狀態,保存在全局變量中S?,通常0表示正常退出。
獲得PID:pid_t getpid(void);
返回調用者pid。
獲得父進程PID:pid_t getppid(void);
返回父進程pid。
其他補充:
正常退出方式:exit()、_exit()、return(在main中)。
exit()和_exit()區別:exit()是對__exit()的封裝,都會終止進程并做相關收尾工作,最主要的區別是_exit()函數關閉全部描述符和清理函數后不會刷新流,但是exit()會在調用_exit()函數前刷新數據流。
return和exit()區別:exit()是函數,但有參數,執行完之后控制權交給系統。return若是在調用函數中,執行完之后控制權交給調用進程,若是在main函數中,控制權交給系統。
異常退出方式:abort()、終止信號。
Linux進程控制
進程地址空間(地址空間)
虛擬存儲器為每個進程提供了獨占系統地址空間的假象。
盡管每個進程地址空間內容不盡相同,但是他們的都有相似的結構。X86 Linux進程的地址空間底部是保留給用戶程序的,包括文本、數據、堆、棧等,其中文本區和數據區是通過存儲器映射方式將磁盤中可執行文件的相應段映射至虛擬存儲器地址空間中。
有一些"敏感"的地址需要注意下,對于32位進程來說,代碼段從0x08048000開始。從0xC0000000開始到0xFFFFFFFF是內核地址空間,通常情況下代碼運行在用戶態(使用0x00000000 ~ 0xC00000000的用戶地址空間),當發生系統調用、進程切換等操作時CPU控制寄存器設置模式位,進入內和模式,在該狀態(超級用戶模式)下進程可以訪問全部存儲器位置和執行全部指令。
也就說32位進程的地址空間都是4G,但用戶態下只能訪問低3G的地址空間,若要訪問3G ~ 4G的地址空間則只有進入內核態才行。
進程控制塊(處理機)
進程的調度實際就是內核選擇相應的進程控制塊,被選擇的進程控制塊中包含了一個進程基本的信息。
上下文切換
內核管理所有進程控制塊,而進程控制塊記錄了進程全部狀態信息。每一次進程調度就是一次上下文切換,所謂的上下文本質上就是當前運行狀態,主要包括通用寄存器、浮點寄存器、狀態寄存器、程序計數器、用戶棧和內核數據結構(頁表、進程表、文件表)等。
進程執行時刻,內核可以決定搶占當前進程并開始新的進程,這個過程由內核調度器完成,當調度器選擇了某個進程時稱為該進程被調度,該過程通過上下文切換來改變當前狀態。
一次完整的上下文切換通常是進程原先運行于用戶態,之后因系統調用或時間片到切換到內核態執行內核指令,完成上下文切換后回到用戶態,此時已經切換到進程B。
請輸入評論內容...
請輸入評論/評論長度6~500個字
最新活動更多
- 1 AI狂歡遇上油價破百,全球股市還能漲多久? | 產聯看全球
- 2 OpenAI深夜王炸!ChatGPT Images 2.0實測:中文穩、細節炸,設計師慌了
- 3 6000億美元估值錨定:字節跳動的“去單一化”突圍與估值重構
- 4 Tesla AI5芯片最新進展總結
- 5 連夜測了一波DeepSeek-V4,我發現它可能只剩“審美”這個短板了
- 6 熱點丨AI“瑜亮之爭”:既生OpenClaw,何生Hermes?
- 7 AI界的殺豬盤:9秒刪庫跑路,全員被封號,還繼續扣錢!
- 8 2026,人形機器人只贏了面子
- 9 DeepSeek降價90%:價格屠夫不是身份,是戰略
- 10 AI Infra產業鏈卡在哪里了?


分享













