OS19.【Linux】進程狀態(上)

目錄

1.情景引入

2.操作系統學科對進程狀態的分類

運行狀態

基于時間片的輪轉調度算法

阻塞狀態

等待IO設備的例子

等待其他進程中需要獲取的數據

進程喚醒

掛起狀態(全稱為阻塞掛起狀態)

簡單談談虛擬內存管理

就緒狀態

筆面試題

3.Linux對進程狀態的分類

R和S狀態?

前臺運行

結論

D狀態

實驗:模擬高IO訪問的情況

結論

T和t狀態

T狀態

t狀態

結論

X狀態

4.交換分區的簡單了解

兩個命令查看交換分區


1.情景引入

C語言代碼中的scanf函數會等待用戶的輸入,那么此時的進程處于閑置的狀態

2.操作系統學科對進程狀態的分類

例如《 計算機操作系統?慕課版?》第65頁:

又如?《 操作系統導論 中譯版 》第22頁:

又如《 現代操作系統原理與實現》第77頁

會發現不同的操作系統書籍對進程的狀態的描述都不太一樣,但大致分4類:

運行狀態、阻塞狀態、掛起狀態和就緒狀態

運行狀態

運行狀態:?處于運行隊列中的進程所處的狀態,即進程已經準備好了,可以隨時被調度

現認為計算機中只有一個CPU,進程需要占用CPU資源,操而作系統中有很多進程,那么這些進程相互之間一定存在競爭,可以通過調度器保證CPU資源均衡使用,而老師,調度器的其中一個任務是將進程鏈接到運行隊列中,CPU要運行進程時直接在運行隊列中隊頭進程

例如底層為雙向鏈表結構的運行隊列:

struct running_queue
{struct running_queue* head;struct running_queue* tail;
}

(注意:是進程的PCB在運行隊列中排隊)

基于時間片的輪轉調度算法

思考一個問題:一個進程只要把自己放到CPU上開始運行了,是不是一直要執行完畢才能把自己放下來?

答:如果是死循環呢?如果按上面這樣做,死循環進程會一直占用著CPU的資源,而其他進程得不到執行,會導致操作系統崩潰

那么需要保證進程公平被調度,引入基于時間片的輪轉算法(調度算法中的一種)

每個進程都有一個叫做時間片的東西,是分時操作系統分配給每個正在運行的進程微觀上的一段CPU時間,通常很短

當一個進程的時間片到了,CPU會暫停執行該進程,轉而執行下一個進程,這叫進程切換.暫停執行的進程如果沒有執行完,會繼續排隊

進程切換:?大量的把進程從CPU上放上去,再拿下來的動作?

阻塞狀態

阻塞狀態:進程無法繼續執行,處于正在等待某個資源就緒的狀態

等待的事件可能為:

1. 等待特定設備,例如IO設備

2. 等待操作系統某些服務,例如內核返回數據

3. 等待其他進程中需要獲取的數據

4. 等待子進程退出

等待IO設備的例子

假設進程A要讀取硬件數據,例如鍵盤

先想想操作系統是什么管理硬件的?

答:先描述再組織.描述硬件可以用結構體對象,而組織硬件就是將硬件對應的結構體連接起來

當沒有從鍵盤鍵入數據時,進程A在等待設備,不能放到運行隊列中,要放到等待隊列(每個硬件的結構體中有等待隊列)中

由于處于阻塞狀態的進程的PCB在等待隊列中,不在運行隊列中,則進程不占用CPU資源,因此在用戶看來,進程"卡"住了

等待其他進程中需要獲取的數據

之前在OS8.【Linux】基本權限(上)文章提到過,fifo可用于終端之間的通信,現在演示阻塞狀態

先創建fifo文件:

mkfifo myfifo

再用XShell復制一份選項卡:

寫入字符串時,如果另一個終端沒有接收會導致進程阻塞:

如果另一個終端接收了:

原理:

命名管道是一端寫入另一端讀取的通信機制,在寫入命名管道的時如果沒有任何進程在讀取,它就會阻塞,直到有一個讀取方連接上來

進程喚醒

定義: 從阻塞狀態到運行狀態

掛起狀態(全稱為阻塞掛起狀態)

1.當操作系統的內存資源嚴重不足時,為了保證操作系統自己運行正常,需要節省內存資源

2.如果某個進程在等待,它無事可做,那么操作系統就保留該進程的PCB,但代碼和數據放到外設(磁盤)中,這叫調離內存,也稱為換出

了解: 如何確定進程在內存中還是在外設中,可以看段描述符

?

(摘自《x86匯編語言:從實模式到保護模式 第二版》)

簡單談談虛擬內存管理

當程序超出了物理內存的大小時,或者操作系統無法分配這么大的物理內存空間時,操作系統要使用虛擬內存管理

下面摘自《x86匯編語言:從實模式到保護模式 第二版》

3.掛起狀態:處于調離內存狀態的進程

4.當條件允許時,操作系統會將該進程調回內存,也稱為換入.如果這個進程所有資源已經就緒了,那么只剩調度了,就會按操作系統設計的調度算法來調度進程,可以認為該進程處于運行狀態

5.掛起狀態全稱為阻塞掛起狀態: 只要是等待資源的進程都可以說阻塞

就緒狀態

就緒狀態:?處于已準備好執行的狀態的進程?即滿足調度的條件了,但是CPU沒調度他(預備執行)

*注:就緒狀態和運行狀態不用區分那么仔細,因為因為CPU調度是很快的,一般只要進程在運行隊列里面,就可以認為是運行狀態

筆面試題

得物二面:阻塞態和就緒態會占用CPU嗎?

答: 1.阻塞態從大的角度說是不影響的,因為阻塞是阻塞在IO或者其他上了,自然不被CPU調度,不占用CPU?2.就緒態從大的角度說是等待被調度,而等待被調度自然還沒有占用CPU

科大訊飛筆試:進程的狀態? 什么情況觸發就緒,什么情況觸發阻塞?

答:見上方總結

快手一面;就緒態和運行態的區別?

答:見上方總結

3.Linux對進程狀態的分類

看看Linux內核源代碼對進程狀態的定義:

fs/proc/array.c下:https://github.com/torvalds/linux/blob/master/fs/proc/array.c

/** The task state array is a strange "bitmap" of* reasons to sleep. Thus "running" is zero, and* you can test for combinations of others with* simple bit tests.*/
static const char * const task_state_array[] = {/* states in TASK_REPORT: */"R (running)",		/* 0x00 */"S (sleeping)",		/* 0x01 */"D (disk sleep)",	/* 0x02 */"T (stopped)",		/* 0x04 */"t (tracing stop)",	/* 0x08 */"X (dead)",		/* 0x10 */"Z (zombie)",		/* 0x20 */"P (parked)",		/* 0x40 *//* states beyond TASK_REPORT: */"I (idle)",		/* 0x80 */
};

以這個測試代碼為例說明R和S狀態:

#include <stdio.h>
#include <unistd.h>
int main()
{while(1){printf("The process is runnning...\n");}return 0;
}

R和S狀態?

運行上方代碼,再開一個終端捕獲該進程的運行狀態:

?發現多次捕獲發現a.out進程都是"S+"狀態.不是R狀態

答:這是一個概率問題,R狀態相比S狀態存在的時間極短,此進程絕大部分時間在等待IO設備(這里是顯示器),即處于睡眠狀態S (sleeping)?

又比如bash命令行解釋器,其大部分時間在等待用戶的輸入,處于S狀態

修改以上代碼:

#include <stdio.h>
#include <unistd.h>
int main()
{while(1);return 0;
}

捕獲結果:

執行while(1);是不需要等待顯示器資源的,因此進程處于R狀態,一直在執行

前臺運行

注:R+和S+的+指的是前臺運行,即通過終端展示前臺進程的信息

進一步解釋:進程運行是在內存中通過操作系統的調度算法+ CPU來完成的.進程在運行時,開發者一定是想知道進程的一些調試信息的,所以有的進程會看調用printf、scanf等函數,而這些函數都是與外設來交互的,那么使用printf時,就是向顯示器文件輸出的,即通過終端呈現出來,對于scanf,輸入時,用戶也需要要知道自己輸入了什么,需要在顯示器文件中顯示的,也是通過終端來完成的.因此終端主要是展示前臺進程的信息的
如果是后臺進程,它們的debug信息不可以向終端輸出,只能向文件輸出,也就是日志

1.在bash中執行命令時默認是前臺運行

2.和前臺運行對應的是后臺運行,在命令后加&可以讓進程在后臺運行

例如運行剛剛的程序:

終端返回了進程的PID : 11628

可以用kill來殺死進程,Ctrl+C是沒有用的

結論

R (running)狀態相當于操作系統的運行狀態,而S (sleeping)狀態相當于操作系統的阻塞狀態

D狀態

D狀態:處于等待某些不可中斷的資源狀態的進程

例如進程正在向磁盤中寫入數據時,進程需要等待寫入磁盤的結果

進一步解釋:進程A正在向磁盤中寫入數據時,如果操作系統的內存資源嚴重不足,如果操作系統殺死正在待磁盤寫入結果的進程A,那么設想一下: 如果磁盤寫入失敗,那么磁盤無法報告給進程A,有丟失數據的風險,這會出問題

解決方法:讓進程A在等待磁盤寫入完畢期間,該進程不能被操作系統殺掉,則進程A處于D狀態

對比S狀態和D狀態,S狀態是淺度睡眠,而D狀態是深度睡眠,而且深度睡眠和淺度睡眠都是等待某資源就緒,因此都屬于阻塞狀態

淺度睡眠(S狀態又稱為Interruptible Sleep n.可中斷睡眠)可以被喚醒,而深度睡眠是不能被喚醒的,稱為Uninterruptible Sleep n.不可中斷睡眠,處于D狀態的進程是操作系統(注意主體!!)是無法使用kill命令殺死的,而且該進程不會響應任何請求

以下摘自redhat processstates

Uninterruptible Sleep State
An Uninterruptible sleep state is one that won't handle a signal right away. It will wake only as a result of a waited-upon resource becoming available or after a time-out occurs during that wait (if the time-out is specified when the process is put to sleep).
The Uninterruptible state is mostly used by device drivers waiting for disk or network I/O. When the process is sleeping uninterruptibly, signals accumulated during the sleep are noticed when the process returns from the system call or trap. In Linux systems. the command ps -l uses the letter D in the state field (S) to indicate that the process is in an Uninterruptible sleep state. In that case, the process state flag is set as
follows:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? p->state = TASK_UNINTERRUPTABLE
LEARN MORE: Read more about D states in the Red Hat Knowledgebase:
https://access.redhat.com/knowledge/solutions/59989/

實驗:模擬高IO訪問的情況

模擬處于D狀態的進程,例如生成一個較大的文件:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <cstdlib>
#include <string.h>
#include <random>
#include <ctime>
#include <climits>
#define BUFFER_SIZE 1024 * 1024 * 5//5MB緩沖區
int main() 
{// 分配緩沖區unsigned long long* buffer = (unsigned long long*)malloc(BUFFER_SIZE);if (buffer == NULL) {perror("malloc fail");return -1;}std::uniform_int_distribution<unsigned long long> distribution(0, ULLONG_MAX);std::default_random_engine generator;// 打開文件printf("create random numbers.bin......\n");FILE* fptr = fopen("random numbers.bin", "wb");if (fptr == NULL){perror("Fail to open file!\n");free(buffer);return -1;}printf("writing data......\n");srand((unsigned int)time(NULL));int times =2048;while (times--){//先填滿緩沖區unsigned long long buf_index = 0;while (buf_index < BUFFER_SIZE/8){unsigned long long random = distribution(generator);buffer[buf_index] = random;buf_index++;}printf("write buffer%d,bin file's size:%dMB\n", 2048 - times, (2048 - times)*5);fwrite(buffer, sizeof(unsigned long long), BUFFER_SIZE / sizeof(unsigned long long), fptr);}printf("done!\n");printf("free buffer......\n");free(buffer);printf("close file......\n");fclose(fptr);printf("press any key to quit\n");getchar();return 0;
}

運行結果:

結論

1.D狀態本身是操作系統正常處理IO的表現,一般處于D狀態的進程持續時間較短

2.但如果大量進程持續處于D狀態,會占用大量資源,操作系統會負載,容易產生故障

拓展閱讀可以看看閃客大佬這篇文章:閃客 什么叫進程被 D 了

T和t狀態

T和t狀態的區別暫時不講,當然認為都是暫停狀態

T狀態

例如執行以下代碼

#include <stdio.h>
int main()
{while(1);return 0;
}

使用kill -l命令查看所有能發送的信號

向進程發送19號信號SIGSTOP:

kill -19 92159

再次使用ps命令查看:進程被暫停

向進程發送18號信號可繼續執行:

t狀態

int main()
{return 0;
}

使用gdb(有關gdb的使用參見OS15.【Linux】gdb調試器的簡單使用文章)在return 0處下斷點,

之后使用ps命令查看:發現進程a.out處于t狀態,因為gdb控制了a.out進程

結論

處于T或t狀態的進程可能被其他進程控制

X狀態

X狀態(dead):進程處于終止狀態

注意:X狀態只是一個返回狀態,任務列表里是看不到這個狀態的

4.交換分區的簡單了解

在linux中,將進程換出到磁盤,實際上換出到交換分區(swap分區)

可以在Linux?mint桌面版的系統監視器中看到:

兩個命令查看交換分區

在Linux mint桌面版下演示:

swapon --show

free -h

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/915480.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/915480.shtml
英文地址,請注明出處:http://en.pswp.cn/news/915480.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何優雅地修改項目的 Android 版本(API 級別)

引言 在 Android 開發的日常迭代中&#xff0c;我們經常需要升級或降級項目的 minSdkVersion、targetSdkVersion 與 compileSdkVersion。升級可以解鎖新特性和性能優化&#xff1b;降級則可能為了兼容舊機型或快速驗證問題。本文將手把手演示在 Android Studio 里修改 Android …

GNU Radio多類信號多種參數數據集生成技巧

參考我的這篇博客&#xff0c;我想自制一個多信號數據集&#xff1a; 【多雷達信號硬件模擬】 3臺USRP1臺VSG信號發生器模擬多雷達信號&#xff0c;1臺USRP產生高斯噪聲模擬更多信道環境&#xff0c;1臺USRP采集信號 需要在多個波段對四種信號進行參數設置&#xff0c;帶寬有…

Ansible + Shell 服務器巡檢腳本

腳本概述這是一個用于服務器日常巡檢的 Shell 腳本&#xff0c;主要功能包括&#xff1a;檢查多臺主機的網絡連通性 監控CPU、內存和磁盤使用率 生成詳細的巡檢報告 通過企業微信發送告警通知核心技術點1. 主機批量管理使用Ansible工具遠程執行命令和腳本 通過主機…

Linux-rpm和yum

一、RPMRPM&#xff08;Red Hat Package Manager&#xff09;是一個用于管理 Red Hat 系列 Linux 發行版&#xff08;如 RHEL、CentOS、Fedora&#xff09;軟件包的工具。RPM 允許用戶以統一的格式來安裝、卸載、升級和查詢軟件包。它是 .rpm 文件的主要工具&#xff0c;后綴名…

手推OpenGL相機的正交投影矩陣和透視投影矩陣(附源碼)

概述計算OpenGL的正交投影矩陣和透視投影矩陣是有現成函數的。自己手推不是為了重復造輪子。手推一遍&#xff0c;可以極大的加強對這兩個矩陣的理解。同時也可以滿足一下自己求知欲。正交投影矩陣手推正交投影矩陣源碼 WGMatrix4x4 WGMatrix4x4::BuildOrtho(double l, double …

【跨國數倉遷移最佳實踐2】MaxCompute SQL執行引擎對復雜類型處理全面重構,保障客戶從BigQuery平滑遷移

本系列文章將圍繞東南亞頭部科技集團的真實遷移歷程展開&#xff0c;逐步拆解 BigQuery 遷移至 MaxCompute 過程中的關鍵挑戰與技術創新。本篇為第二篇&#xff0c;跨國數倉遷移背后 MaxCompute 的統一存儲格式創新。 注&#xff1a;客戶背景為東南亞頭部科技集團&#xff0c;…

react(基礎篇)

React由Meta公司研發&#xff0c;用于構建Web和原生交互界面的庫。 React 官方中文文檔 查看JSX &#xff08;一&#xff09;React組件 用戶界面的一部分&#xff0c;通俗的來講&#xff0c;最小的元素組成的單元&#xff0c;可以實現部分邏輯與功能 房子的門就可以看成一個…

數據結構-哈希表(一)哈希函數、哈希表介紹、優缺點

哈希表 哈希函數哈希表使用了哈希函數來完成key到地址的快速映射&#xff0c;所以在了解哈希表之前&#xff0c;需要先明白哈希函數的概念和特點。 哈希函數的定義 哈希函數 哈希函數是一種將任意長度輸入的數據&#xff0c;轉換成固定長度輸出的算法哈希函數H可以表示為yH(x) …

Shader開發(一)什么是渲染

前言在現代游戲開發和計算機圖形學領域&#xff0c;渲染技術是連接虛擬世界與視覺呈現的關鍵橋梁。無論你是剛接觸圖形編程的新手&#xff0c;還是希望深入理解渲染原理的開發者&#xff0c;掌握渲染的核心概念都是必不可少的第一步。什么是渲染&#xff1f;渲染&#xff08;Re…

策略模式+工廠模式(案例實踐易懂版)

最近,可以說這2025年度,自己更文的次數都大大減少,主要最近大環境不景氣,自己職業也受到波及,學習的東西也是因為AI而變得更多, 沒辦法,你不學,總有人會學,關于AI的我也準備出個專輯,相信絕對幫助到大家 額,好像說多了,言歸正傳,我們看一下今天的主題:策略模式工廠模式 本文主要…

【NLP輿情分析】基于python微博輿情分析可視化系統(flask+pandas+echarts) 視頻教程 - snowNLP庫實現中文情感分析

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;最近寫了一套【NLP輿情分析】基于python微博輿情分析可視化系統(flaskpandasecharts)視頻教程&#xff0c;持續更新中&#xff0c;計劃月底更新完&#xff0c;感謝支持。今天講解snowNLP庫實現中文情感分析 視頻在線地址&…

大根堆,小根堆,雙指針

碼蹄集OJ-大約 #include<bits/stdc.h> using namespace std; priority_queue<int>max2,maxDel; priority_queue<int,vector<int>,std::greater<int>>min2,minDel; const int N1e51; int n,result0,a[N]; int main( ) {cin>>n;for(int i1…

RS485和Modbus

UART協議中&#xff0c;空閑狀態為高電平&#xff0c;也就是1,R25和R27&#xff0c;485收發器特性MAX485 (美信)SSP485 (國產替代)AZRS3080 (安格)供電電壓5V5V3.3V ~ 5.5V靜態電流300μA (接收模式)120μA (接收模式)150μA (接收模式)傳輸速率2.5Mbps10Mbps20Mbps總線負載能力…

【Android】交叉編譯faiss庫 | 問題解決

目錄 一 解決 FAISS 交叉編譯到 Android 時的 BLAS/MKL 依賴問題 二 交叉編譯faiss ■禁用 BLAS并交叉編譯faiss ■使用 OpenBLAS 的 Android 移植版本并交叉編譯faiss 三 報錯處理 ■報錯 ■SWIG 一 解決 FAISS 交叉編譯到 Android 時的 BLAS/MKL 依賴問題

《使用 IDEA 部署 Docker 應用指南》

使用 IDEA 部署 Docker 應用的詳細步驟 一、創建 Dockerfile 配置文件 在項目根目錄下創建Dockerfile文件&#xff0c;配置內容如下&#xff1a; # 使用官方的OpenJDK鏡像作為基礎鏡像 FROM openjdk:17-jdk-slim# 設置維護者信息(可選) LABEL maintainer"三木豪"# 設…

【Docker#3】Window 和 Linux 上 docker安裝 相關知識

前置了解&#xff1a; X86 高并發&#xff1a;基于 x86 架構的處理器&#xff0c;在高負載下處理大量并發請求的能力。ARM &#xff1a;使用 ARM 架構處理器的移動設備&#xff0c;具有低功耗和高性能的特點。 操作系統&#xff1a; CentOS&#xff1a;基于 Red Hat Enterprise…

一次 POI 版本升級踩坑記錄

前言 結論先行。 開發過程中由于可能涉及到二次開發&#xff0c;若原系統開發時間久遠&#xff0c;沒有達成一致規范設計&#xff0c;導致風格各異&#xff0c;確實滿足當時開發場景&#xff0c;但增大了后續的更新的難度&#xff0c;容易出現俄羅斯套娃現象&#xff0c;新的更…

硬件設計學習DAY13——電源緩沖電路設計全解

每日更新教程&#xff0c;評論區答疑解惑&#xff0c;小白也能變大神&#xff01;" 目錄 一.緩沖電路介紹 1.1緩沖電路的作用 1.2寄生參數的來源 1.3緩沖電路的類型 1.4常見緩沖電路設計 1.5設計原則 二.吸收與緩沖 2.1吸收與緩沖的核心作用 2.2電壓尖峰與吸收措…

鴻蒙搜狐新聞如何在Native調用ArkTS方法

01前言鴻蒙作為一款新興的智能操作系統&#xff0c;現在適配鴻蒙系統的應用越來越多&#xff0c;同時會面臨三端兼容問題&#xff0c;如同一產品功能&#xff0c;需要維護iOS、Android、鴻蒙三端代碼。拿文件上傳、下載功能場景舉例&#xff0c;同時要適配iOS、Android、鴻蒙三…

Java行為型模式---中介者模式

中介者模式基礎概念中介者模式&#xff08;Mediator Pattern&#xff09;是一種行為型設計模式&#xff0c;其核心思想是通過一個中介對象來封裝一系列對象之間的交互&#xff0c;使各對象不需要顯式地相互引用&#xff0c;從而降低耦合度&#xff0c;并可以獨立地改變它們之間…