操作系统进程学习(Linux 内核学习笔记)
操作系統(tǒng)進程學習(Linux 內(nèi)核學習筆記)
進程優(yōu)先級
并非所有進程都具有相同的重要性。除了大多數(shù)我們所熟悉的進程優(yōu)先級之外,進程還有不同的關(guān)鍵度類別,以滿足不同需求。首先進程比較粗糙的劃分,進程可以分為實時進程 和非實時進程(普通進程)。
實時進程優(yōu)先級(0-99)都比普通 進程的優(yōu)先級(100-139)高。當系統(tǒng)中有實時進程運行時,普通進程幾乎無法分到時間片(只能分到5%的CPU時間)。
進程系統(tǒng)調(diào)用
? 討論fork和exec系列系統(tǒng)調(diào)用的實現(xiàn)。通常這些調(diào)用不是由應(yīng)用程序直接發(fā)出的,而是通過一個中間層調(diào)用,即負責與內(nèi)核通信的C標準庫。從用戶狀態(tài)切換到核心態(tài)的方法,依不同的體系結(jié)構(gòu)而各有不同
用戶發(fā)起一個新進程之后,CPU為進程分配資源,并將硬盤數(shù)據(jù)讀到內(nèi)存中去,但是用戶進程是一個應(yīng)用級程序,無法直接與CPU進行交互,所以通過系統(tǒng)調(diào)用(system_call),加載完成內(nèi)核就會退出CPU,用戶進程執(zhí)行完畢后,內(nèi)核進入CPU將用戶進程移除,下一個同上
進程復制
(1) fork是重量級調(diào)用,因為它建立了父進程的一個完整副本,然后作為子進程執(zhí)行。 為減少與該調(diào)用相關(guān)的工作量,Linux使用了寫時復制(copy-on-write)1技術(shù)。
(2) vfork類似于fork,但并不創(chuàng)建父進程數(shù)據(jù)的副本。相反,父子進程之間共享數(shù)據(jù)。 這節(jié)省了大量CPU時間(如果一個進程操縱共享數(shù)據(jù),則另一個會自動注意到)。
(3) clone產(chǎn)生線程,可以對父子進程之間的共享、復制進行精確控制。
調(diào)度器分析
調(diào)度器及其功能
內(nèi)核中用來安排進程執(zhí)行的模塊稱為調(diào)度器(scheduler),它可以切換進程狀態(tài) (process state)。例如執(zhí)行、可中斷睡眠、不可中斷睡眠、退出、暫停等。 調(diào)度器是CPU中央處理器的管理員,主要負責完成做兩件事情:一、選擇某些就緒進 程來執(zhí)行,二是打斷某些執(zhí)行的進程讓它們變?yōu)榫途w狀態(tài)。調(diào)度器分配CPU時間的基本依據(jù)就 是進程的優(yōu)先級。上下文 切換(context switch):將進程在CPU中切換執(zhí)行的過程,內(nèi)核承擔 此任務(wù),負責重建和存儲被切換掉之前的CPU狀態(tài)
主要有兩個函數(shù)可以獲得線程設(shè)置的最高和最低優(yōu)先級:
int sched_get_priority_max(int); // 獲取實時優(yōu)先級最大值 int sched_get_priority_min(int); // 獲取實時優(yōu)先級最小值設(shè)置與獲取優(yōu)先級各個主要函數(shù):
int pthread_attr_setschedparam(pthread_attr_t*,const struct sched_param);//創(chuàng)建線程優(yōu)先級 int pthread_attr_getschedparam(pthread_attr_t*,const struct sched_param);//獲取線程優(yōu)先級實戰(zhàn):
#include <assert.h> #include <iostream> #include <pthread.h> #include <sched.h> #include <stdio.h>static int get_thread_policy(pthread_attr_t *attr) //獲取線程調(diào)度策略 {int plicy;int rs = pthread_attr_getschedpolicy(attr, &plicy);assert(rs == 0);switch (plicy){case SCHED_FIFO:printf("policy = FIFO");break;case SCHED_RR:printf("policy = RR");break;case SCHED_OTHER:printf("policy=OTHER");break;default:printf("policy = unknown");break;}return plicy; }static void show_thread_priority(pthread_attr_t *attr, int policy) {int priority = sched_get_priority_max(policy);assert(priority != -1);printf("max_priority=%d\n", priority);priority = sched_get_priority_min(policy);assert(priority != -1);printf("min_priority=%d\n", priority); }static int get_thread_priority(pthread_attr_t *attr) //獲取線程優(yōu)先級 {sched_param param;int rs = pthread_attr_getschedparam(attr, ¶m);assert(rs == 0);printf("priority = %d", param.sched_priority);return param.sched_priority; } static void set_thread_policy(pthread_attr_t *attr, int policy) {int rs = pthread_attr_setschedpolicy(attr, policy);assert(rs == 0);get_thread_policy(attr); }int main(int argc, char const *argv[]) {pthread_attr_t attr;struct sched_param sched;int rs = pthread_attr_init(&attr);assert(rs == 0);int plicy = get_thread_policy(&attr);printf("輸出進程優(yōu)先級\n");show_thread_priority(&attr, plicy);printf("輸出FIFO優(yōu)先級");show_thread_priority(&attr, SCHED_FIFO);printf("輸出RR優(yōu)先級\n");show_thread_priority(&attr, SCHED_RR);printf("輸出當前線程優(yōu)先級");int priority = get_thread_priority(&attr);printf("設(shè)置線程策略\n");printf("設(shè)置FIFO策略");set_thread_policy(&attr, SCHED_FIFO);printf("設(shè)置RR策略");set_thread_policy(&attr, SCHED_RR);printf("還原線程屬性\n");set_thread_policy(&attr, plicy);rs = pthread_attr_destroy(&attr);assert(rs == 0);return 0; }實戰(zhàn)2
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h>void threadfunc1() {sleep(1);int policy;struct sched_param praram;pthread_getschedparam(pthread_self(), &policy, &praram);if (policy == SCHED_OTHER)printf("SCHED_OTHER.\n");if (policy == SCHED_RR);printf("SCHED_RR 1.\n");if (policy == SCHED_FIFO)printf("SCHED_FIFO.\n");for (int i = 1; i <= 10; i++){for (int j = 1; j < 4000000; j++){}printf("Threadfunc1.\n");}printf("pthreadfunc1 EXIT.\n"); }void threadfunc2() {sleep(1);int policy;struct sched_param praram;pthread_getschedparam(pthread_self(), &policy, &praram);if (policy == SCHED_OTHER)printf("SCHED_OTHER.\n");if (policy == SCHED_RR);printf("SCHED_RR 1.\n");if (policy == SCHED_FIFO)printf("SCHED_FIFO.\n");for (int i = 1; i <= 10; i++){for (int j = 1; j < 4000000; j++){}printf("Threadfunc2.\n");}printf("pthreadfunc2 EXIT.\n"); }void threadfunc3() {sleep(1);int policy;struct sched_param praram;pthread_getschedparam(pthread_self(), &policy, &praram);if (policy == SCHED_OTHER)printf("SCHED_OTHER.\n");if (policy == SCHED_RR);printf("SCHED_RR 1.\n");if (policy == SCHED_FIFO)printf("SCHED_FIFO.\n");for (int i = 1; i <= 10; i++){for (int j = 1; j < 4000000; j++){}printf("Threadfunc3.\n");}printf("pthreadfunc3 EXIT.\n"); }int main() {int i;i = getuid();if (i == 0)printf("the current user is root.\n");elseprintf("the current user is not root.\n");pthread_t ppid1, ppid2, ppid3;struct sched_param param;pthread_attr_t attr1, attr2, attr3;pthread_attr_init(&attr2);pthread_attr_init(&attr1);pthread_attr_init(&attr3);param.sched_priority = 51;pthread_attr_setschedpolicy(&attr3, SCHED_RR);pthread_attr_setschedparam(&attr3, ¶m);pthread_attr_setinheritsched(&attr3, PTHREAD_EXPLICIT_SCHED);param.sched_priority = 22;pthread_attr_setschedpolicy(&attr2, SCHED_RR);pthread_attr_setschedparam(&attr2, ¶m);pthread_attr_setinheritsched(&attr2, PTHREAD_EXPLICIT_SCHED);pthread_create(&ppid3, &attr1, (void *)threadfunc3, NULL);pthread_create(&ppid2, &attr2, (void *)threadfunc2, NULL);pthread_create(&ppid1, &attr3, (void *)threadfunc1, NULL);pthread_join(ppid3, NULL);pthread_join(ppid2, NULL);pthread_join(ppid1, NULL);pthread_attr_destroy(&attr3);pthread_attr_destroy(&attr2);pthread_attr_destroy(&attr1);return 0; }RCU機制
? RCU英文全稱為Read-Copy-Update,顧名思義就是 “讀 - 拷貝-更新”,是內(nèi)核中重要 的同步機制。Linux內(nèi)核已有原子操作、讀寫信號量等等鎖機制,為何會單獨設(shè)計一個比較復雜的新機制?
RCU原理
? RCU記錄所有指向共享數(shù)據(jù)的指針的使用者,當要修改該共享數(shù)據(jù)時,首先創(chuàng)建一個 副本,在副本中修改。所有讀訪問線程都離開讀臨界區(qū)之后 ,指針指向新的修改后副本的指針,并且刪除舊數(shù)據(jù)
RCU優(yōu)點:讀者開銷少,不需要鎖,原子指令,內(nèi)存屏障等,無死鎖問題,無內(nèi)存泄露風險
RCU缺點:寫者同步開銷比較大,寫著之間需要互斥處理,同步機制復雜
內(nèi)核內(nèi)存布局
? ARM64架構(gòu)處理器采用48位物理尋址機制,最大可尋找256TB的物理地址空間。對于 目前應(yīng)用完全足夠,不需要擴展到64位的物理尋址。虛擬地址也同樣最大支持48位尋址,所以 在處理器架構(gòu)設(shè)計上,把虛擬地址空間劃分為兩個空間,每個空間最大支持256TB,linux內(nèi)核 在大多數(shù)體系結(jié)構(gòu)上都把兩個地址劃分為:用戶空間和內(nèi)核空間。
用戶空間:0x0000_0000_0000_0000至0x0000_ffff_ffff_ffff。
內(nèi)核空間:0xffff_0000_0000_0000至0xffff_ffff_ffff_ffff
總結(jié)
以上是生活随笔為你收集整理的操作系统进程学习(Linux 内核学习笔记)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 还在用 Notepad++吗? 盘点五款
- 下一篇: linux群ping服务器各网段脚本