您好,登錄后才能下訂單哦!
這篇“Linux的進程線程及調度的概念是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Linux的進程線程及調度的概念是什么”文章吧。
操作系統中的經典定義: 進程:資源分配單位。 線程:調度單位。 操作系統中用PCB(Process Control Block, 進程控制塊)來描述進程。Linux中的PCB是task_struct結構體。
R, TASK_RUNNING:就緒態或者運行態,進程就緒可以運行,但是不一定正在占有CPU S, TASK_INTERRUPTIBLE:淺度睡眠,等待資源,可以響應信號,一般是進程主動sleep進入的狀態 D, TASK_UNINTERRUPTIBLE:深度睡眠,等待資源,不響應信號,典型場景是進程獲取信號量阻塞 Z, TASK_ZOMBIE:僵尸態,進程已退出或者結束,但是父進程還不知道,沒有回收時的狀態 T, TASK_STOPED:停止,調試狀態,收到SIGSTOP信號進程掛起
1) system() 通過調用shell啟動一個新進程
2) exec() 以替換當前進程映像的方式啟動一個新進程
3) fork() 以復制當前進程映像的方式啟動一個新進程,子進程中fork()返回0,父進程fork()返回為子進程ID。
4) wait() 父進程掛起,等待子進程結束。
5) 孤兒進程與僵尸進程 孤兒進程:一個父進程退出,而它的一個或多個子進程還在運行,那么那些子進程將成為孤兒進程。孤兒進程將被init進程(進程號為1)所收養,并由init進程對它們完成狀態收集工作。孤兒進程不會浪費資源。 僵尸進程:一個進程使用fork創建子進程,如果子進程退出,而父進程并沒有調用wait或waitpid獲取子進程的狀態信息,那么子進程的進程描述符仍然保存在系統中。這種進程稱之為僵尸進程。僵尸進程浪費系統資源(進程描述符task_struct存在,進程占用的資源被回收,不存在內存泄漏,實際上基本不浪費系統資源,參宋寶華的課程)。 避免僵尸進程: 僵尸進程產生原因: 1、子進程結束后向父進程發出SIGCHLD信號,父進程默認忽略了它; 2、父進程沒有調用wait()或waitpid()函數來等待子進程的結束。 避免僵尸進程方法: 1、父進程調用wait()或者waitpid()等待子進程結束,這樣處理父進程一般會阻塞在wait處而不能處理其他事情。 2、捕捉SIGCHLD信號,并在信號處理函數里面調用wait函數,這樣處理可避免1中描述的問題。 3、fork兩次,父進程創建兒子進程,兒子進程再創建一個孫子進程,然后兒子進程自殺,孫子進程成為孤兒進程被init進程收養。
1) 信號 信號這里指的是事件。比如按CTRL-C組合鍵會發送SIGINT信號,進程里可以捕捉到這個信號進行相應處理。
2) 管道PIPE 一切皆文件,管道的操作也是類似文件的操作。 popen()函數類似于fopen()函數,返回的是對象指針。 pipe()函數類似于open()函數,返回的是對象描述符。 管道是在親屬進程(同一父進程創建出的相關進程)之間進行數據傳輸的。
3) 命名管道FIFO 命名管道可用于無親屬關系的進程間通信。 mkfifo()/mknod()將在文件系統中創建一個有路徑和名稱的文件。把這個管道文件當作普通文件用就行了,就可以實現進程間通信。
4) 信號量 信號量、消息隊列、共享內存是System V IPC機制。 臨界區:任何時刻只能有一個進程進行獨占式訪問的代碼區。 信號量:大部分進程間通信只需要二進制信號量,因此這里只討論二進制信號量。進入臨界區前,執行P操作(若信號量大于1則減1并進入臨界區,否則掛起本進程);退出臨界區時,執行V操作(若有進程在等待掛起則喚醒之,否則信號量加1)。 互斥量:互斥信號量是二進制信號量的一個子集。
5) 消息隊列 與命名管道類似,但不必考慮打開/關閉管道的復雜操作。消息隊列獨立于進程而存在。
6) 共享內存 需要通信的進程間共享一塊內存進行數據交換。
Linux調度器實際是識別task_struct進行調度。 無論進程線程,底層都對應一個task_struct,進程和線程的區別是共享資源的多少,兩個進程間完全不共享資源,兩個線程間共享所有資源。
執行fork后,父進程的task_struck對拷給子進程,父子進程最初資源完全一樣,但是是兩份不同的拷貝,因此任何改動都造成二者的分裂。
父子進程對內存資源(mm)的管理使用了COW(Copy-On-Write, 寫時拷貝)技術:
在fork之前,一片內存區對應一份物理地址和一份虛擬地址,內存區的權限為RW;
在fork之后,父子進程看到的內存區虛擬地址相同,物理地址也相同,父子進程使用的其實是同一片物理內存,未發生內存拷貝,操作系統會將此內存區權限改為RO;
父或子進程對內存區執行寫操作將觸發PageFault,操作系統此時會將內存區拷貝一份,父子進程看到的虛擬地址仍然一樣,但是物理地址已經不同。各進程虛擬地址到物理地址的映射由MMU(Memory Management Unit, 內存管理單元)管理。
fork運行在有MMU的CPU上。
對于無MMU的CPU,無法應用COW,無法支持fork。 無MMU的CPU使用vfork創建進程,父進程將一直阻塞直到子進程exit或exec。 vfork和fork的本質區別是,vfork中的父子進程共用同一片內存區。
Linux線程本質上就是進程,只是與進程間資源共享方式不同,線程間共享所有資源,如上圖所示。 每個線程都有自己的task_struct,因此每個線程都可被CPU調度。多線程間又共享同一進程資源。這兩點剛好滿足線程的定義。 Linux就是這樣用進程實現了線程,所以線程又稱為輕量級進程。
POSIX要求,同一進程的多個線程獲取進程ID是得到的是唯一ID值。
Linux同一進程的多線程,在內核視角實際上每個線程都有一個PID,但在用戶空間需要getpid返回唯一值,Linux使用了一個小技巧,引入了TGID的概念,getpid()返回的的TGID值。
進程視角的top命令: 不帶參數的top命令(默認情況),顯示的是進程對單核CPU的利用率,例如,一個進程內有三個線程,主線程創建了線程1和線程2,線程1和線程2都調用一個while(1),則對雙核CPU而言,線程1和線程2各用一個核,占用率都是100%,則top命令看到的進程CPU利用率是200%,進程ID是主線程的PID(也就是TGID)。
線程視角的top命令: top –H命令從線程視角顯示CPU占用率,上例中,將會顯示,線程1占用率100%,線程2占用率100%。 說線程的PID,是指用戶空間的進程ID,值就是TGID;當特別指出,線程在內核空間的PID,則指線程在內核中task_struct里特有的PID。
SCHED_FIFO:不同優先級按照優先級高的先跑到睡眠,優先級低的再跑;同等優先級先進先出。 SCHED_RR:不同優先級按照優先級高的先跑到睡眠,優先級低的再跑;同等優先級輪轉。 內核RT補丁:
如下兩個參數 /proc/sys/kernel/sched_rt_period_us /proc/sys/kernel/sched_rt_runtime_us 表示在period的時間里RT最多只能跑runtime的時間
SCHED_OTHER:
進程有IO消耗性和CPU消耗型兩種衡量參數。 優先級高的意味著:1) 得到更多的時間片,2) 醒時能搶占優先級低的。時間片輪轉。 內核存儲靜態優先級,用戶可通過nice來修改靜態優先級。 進程的動態優先級則是根據靜態優先級實時計算出來的,調度算法獎勵IO消耗性(調高優先級增加實時性)、處罰CPU消耗型(調低優先級減小實時性)
紅黑樹,左邊節點小于右邊節點的值 運行到目前為止vruntime最小的進程 同時考慮了CPU/IO和nice 總是找vruntime最小的線程調度。 vruntime = pruntime/weight × 1024; vruntime是虛擬運行時間,pruntime是物理運行時間,weight權重由nice值決定(nice越低權重越高),則運行時間少、nice值低的的線程vruntime小,將得到優先調度。這是一個隨運行而動態變化的過程。
工具chrt和renice:
1 2 3 4 5 設置SCHED_FIFO和50 RT優先級 # chrt -f -a -p 50 10576 設置nice # renice -n -5 -g 9394 # nice -n 5 ./a.out
以上就是關于“Linux的進程線程及調度的概念是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。