?? 個(gè)人主頁——??開著拖拉機(jī)回家_Linux,大數(shù)據(jù)運(yùn)維-CSDN博客 ?????
???????????????? ?????????????? ????????????????????????
感謝點(diǎn)贊和關(guān)注 ,每天進(jìn)步一點(diǎn)點(diǎn)!加油!
目錄
一、基本概念
1.1 概念提出
1.2 特征
二、描述進(jìn)程-PCB
2.1 什么是進(jìn)程控制塊PCB
2.2 task_struct內(nèi)容分類(成員)
2.3 進(jìn)程控制塊如何對進(jìn)程進(jìn)行管理的呢?
三、查看進(jìn)程
3.1 通過系統(tǒng)目錄查看
3.2 通過用戶級工具ps查看
四、通過系統(tǒng)調(diào)用獲取進(jìn)程標(biāo)識符(PID)
4.1 使用getpid和getppid
五、通過系統(tǒng)調(diào)用創(chuàng)建進(jìn)程-fork初識
5.1 fork函數(shù)
5.2 fork函數(shù)創(chuàng)建子進(jìn)程
六、Linux進(jìn)程狀態(tài)
七、兩種特殊進(jìn)程
7.1 僵尸進(jìn)程
7.2 孤兒進(jìn)程
一、基本概念
1.1 概念提出
進(jìn)程(Process)是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。在早期面向進(jìn)程設(shè)計(jì)的計(jì)算機(jī)結(jié)構(gòu)中,進(jìn)程是程序的基本執(zhí)行實(shí)體;在當(dāng)代面向線程設(shè)計(jì)的計(jì)算機(jī)結(jié)構(gòu)中,進(jìn)程是線程的容器。程序是指令、數(shù)據(jù)及其組織形式的描述,進(jìn)程是程序的實(shí)體(百度百科)。
1.2 特征
- 動(dòng)態(tài)性:進(jìn)程的實(shí)質(zhì)是程序在多道程序系統(tǒng)中的一次執(zhí)行過程,進(jìn)程是動(dòng)態(tài)產(chǎn)生,動(dòng)態(tài)消亡的。
- 并發(fā)性:任何進(jìn)程都可以同其他進(jìn)程一起并發(fā)執(zhí)行
- 獨(dú)立性:進(jìn)程是一個(gè)能獨(dú)立運(yùn)行的基本單位,同時(shí)也是系統(tǒng)分配資源和調(diào)度的獨(dú)立單位;
- 異步性:由于進(jìn)程間的相互制約,使進(jìn)程具有執(zhí)行的間斷性,即進(jìn)程按各自獨(dú)立的、不可預(yù)知的速度向前推進(jìn)
- 結(jié)構(gòu)特征:進(jìn)程由程序、數(shù)據(jù)和進(jìn)程控制塊三部分組成。
多個(gè)不同的進(jìn)程可以包含相同的程序:一個(gè)程序在不同的數(shù)據(jù)集里就構(gòu)成不同的進(jìn)程,能得到不同的結(jié)果;但是執(zhí)行過程中,程序不能發(fā)生改變。
二、描述進(jìn)程-PCB
引入一個(gè)新概念: 進(jìn)程控制塊PCB(process control block)。PCB就是進(jìn)程屬性的集合(數(shù)據(jù)結(jié)構(gòu)),里面存儲的是進(jìn)程信息。
2.1 什么是進(jìn)程控制塊PCB
進(jìn)程信息被放在一個(gè)叫做進(jìn)程控制塊的數(shù)據(jù)結(jié)構(gòu)中,可以理解為進(jìn)程屬性的集合,稱之為PCB(process control block),Linux操作系統(tǒng)下的PCB是: task_struct。
即task_struct是Linux內(nèi)核的一種數(shù)據(jù)結(jié)構(gòu),它會被裝載到RAM(內(nèi)存)里并且包含進(jìn)程的信息。
2.2 task_struct內(nèi)容分類(成員)
- 標(biāo)示符(PID): 描述本進(jìn)程的唯一標(biāo)示符,用來區(qū)別其他進(jìn)程(每次啟動(dòng)都會變化)。
- 狀態(tài): 任務(wù)狀態(tài),退出代碼,退出信號等。
- 優(yōu)先級: 相對于其他進(jìn)程的優(yōu)先級。
- 程序計(jì)數(shù)器(pc): 程序中即將被執(zhí)行的下一條指令的地址。
- 內(nèi)存指針: 包括程序代碼和進(jìn)程相關(guān)數(shù)據(jù)的指針,還有和其他進(jìn)程共享的內(nèi)存塊的指針。
- 上下文數(shù)據(jù): 進(jìn)程執(zhí)行時(shí)處理器的寄存器中的數(shù)據(jù)。
- I/O狀態(tài)信息: 包括顯示的I/O請求,分配給進(jìn)程的I/O設(shè)備和被進(jìn)程使用的文件列表。
- 記賬信息: 可能包括處理器時(shí)間總和,使用的時(shí)鐘總和,時(shí)間限制,記賬號等。
- 其他信息
2.3 進(jìn)程控制塊如何對進(jìn)程進(jìn)行管理
- 磁盤中的可執(zhí)行程序在將要運(yùn)行時(shí),所有的進(jìn)程中的數(shù)據(jù)(并不是程序本身)加載到內(nèi)存中,此時(shí)操作系統(tǒng)會建立起一個(gè)PCB來保存每一個(gè)程序的信息;
- 這個(gè)時(shí)候PCB就會對每一個(gè)進(jìn)程都建立起相應(yīng)的結(jié)構(gòu)體(即進(jìn)程控制塊)將對應(yīng)的進(jìn)程的屬性、代碼等匹配的傳到這個(gè)結(jié)構(gòu)體中:(這就是先描述)
- 此時(shí),操作系統(tǒng)就會將每一個(gè)進(jìn)程控制塊都連接起來,形成鏈表結(jié)構(gòu),并返回頭結(jié)點(diǎn)。這樣便通過數(shù)據(jù)結(jié)構(gòu)的形式將進(jìn)程的信息組織起來。
三、查看進(jìn)程
3.1 通過系統(tǒng)目錄查看
根目錄下的proc目錄,/proc下存儲著進(jìn)程信息。
目錄名為數(shù)字的即為進(jìn)程信息的目錄,每個(gè)目錄內(nèi)存儲著他們對應(yīng)的進(jìn)程信息。而這些數(shù)字對應(yīng)著該進(jìn)程的標(biāo)識符PID。如下查看標(biāo)識符PID=18964的進(jìn)程信息:
我們進(jìn)入進(jìn)程 18964進(jìn)程目錄
3.2 通過用戶級工具ps查看
實(shí)例:ps ajx/ps aux
該命令可以查看所有系統(tǒng)進(jìn)程。如下查看PID=18964的進(jìn)程信息
創(chuàng)建如下測試腳本并執(zhí)行
#!/bin/bash
proc_test()
{
while(true)
do
echo "I am a process!"
sleep 1
done
}
proc_test
## 執(zhí)行
sh proc_test_18964.sh
另外通過指令對進(jìn)程進(jìn)行檢測,檢測它是否運(yùn)行:
ps ajx | head -1 && ps ajx | grep proc_test | grep -v grep
這里grep實(shí)際也是進(jìn)程,且該進(jìn)程內(nèi)包含有proc_test的信息,所以也顯示出來了。-v選項(xiàng)是反向搜索的意思,即過濾掉包含有g(shù)rep內(nèi)容的信息。
- PPID (Parent Process ID):代表這個(gè)進(jìn)程是由哪個(gè)進(jìn)程發(fā)展衍生而來的,亦即父進(jìn)程的代號
- PID (Process ID): 代表這個(gè)進(jìn)程的代號
- PGID(Process Group):PGID就是進(jìn)程所屬的Group的Leader的PID,如果PGID=PID,那么該進(jìn)程是Group Leader
- SID(Session ID):和PGID非常相似,SID就是進(jìn)程所屬的Session Leader的PID,如果SID==PID,那么該進(jìn)程是session leader
- TPGID:終端進(jìn)程組ID
- STAT:進(jìn)程狀態(tài)
四、通過系統(tǒng)調(diào)用獲取進(jìn)程標(biāo)識符(PID)
4.1 使用getpid和getppid
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
pid_t id = getpid();
while (1)
{
printf("I am a process!pid:%d\n", id);
sleep(1);
}
return 0;
}
執(zhí)行上面可執(zhí)行程序并運(yùn)行如下命令進(jìn)行監(jiān)控
while :; do ps ajx | head -1 && ps ajx | grep proc_test | grep -v grep ; sleep 1;done
函數(shù)getppid(獲取父進(jìn)程的進(jìn)程標(biāo)識符),一般在Linux中普通進(jìn)程都有他的父進(jìn)程。
每一個(gè)子進(jìn)程都是由父進(jìn)程創(chuàng)建出來的。
子進(jìn)程只能有一個(gè)父進(jìn)程,父進(jìn)程可以有多個(gè)子進(jìn)程。每次執(zhí)行可執(zhí)行程序,進(jìn)程標(biāo)識符會改變,因?yàn)槊看味紩?chuàng)建新的進(jìn)程。
編寫如下測試代碼
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
pid_t id = getpid();
pid_t fid = getppid();
while (1)
{
printf("I am a process!pid:%d ppid:%d\n", id, fid);
sleep(1);
}
return 0;
}
?執(zhí)行結(jié)果如下圖:
?多次執(zhí)行我們發(fā)現(xiàn)程序多次執(zhí)行子進(jìn)程每次都會創(chuàng)建新的新的進(jìn)程標(biāo)識符,父進(jìn)程標(biāo)識符沒有改變。如下父進(jìn)程是bash命令行解釋器。
五、通過系統(tǒng)調(diào)用創(chuàng)建進(jìn)程-fork初識
5.1 fork函數(shù)
pid_t fork(void);
?一個(gè)進(jìn)程包括代碼、數(shù)據(jù)和分配給進(jìn)程的資源。fork 函數(shù)會新生成一個(gè)進(jìn)程,調(diào)用 fork 函數(shù)的進(jìn)程為父進(jìn)程,新生成的進(jìn)程為子進(jìn)程。在父進(jìn)程中返回子進(jìn)程的 pid,在子進(jìn)程中返回 0,失敗返回-1。
5.2 fork函數(shù)創(chuàng)建子進(jìn)程
創(chuàng)建測試代碼:?
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
pid_t pid;
printf("before fork : pid is : %d, ppid is : %d\n", getpid(), getppid());
pid=fork();
printf("after fork : pid is : %d, ppid is : %d, fork return %d\n", getpid(), getppid(),pid);
sleep(2);
return 0;
}
編譯后執(zhí)行
fork函數(shù)執(zhí)行后,后面的"after fork"執(zhí)行了兩次,8897作為父進(jìn)程創(chuàng)建了子進(jìn)程 8898。也就是說fork之后,代碼共享,從一個(gè)進(jìn)程分為兩個(gè)分支,一為父,一為子。
進(jìn)程調(diào)用fork,當(dāng)控制轉(zhuǎn)移到內(nèi)核中的fork代碼后,內(nèi)核會:
- 分配新的內(nèi)存塊和內(nèi)核數(shù)據(jù)結(jié)構(gòu)給子進(jìn)程;
- 將父進(jìn)程部分?jǐn)?shù)據(jù)結(jié)構(gòu)內(nèi)容拷貝至子進(jìn)程;
- 添加子進(jìn)程到系統(tǒng)進(jìn)程列表當(dāng)中;
- fork返回,開始調(diào)度器調(diào)度;
所以,fork之前父進(jìn)程獨(dú)立執(zhí)行,fork之后父子兩個(gè)執(zhí)行流分別執(zhí)行。注意:fork之后誰先執(zhí)行完全由調(diào)度器決定。
fork它僅僅被調(diào)用一次,卻能夠返回兩次,它可能有三種不同的返回值:
(1) 在父進(jìn)程中,fork返回新創(chuàng)建子進(jìn)程的進(jìn)程ID;
(2)在子進(jìn)程中,fork返回0;
(3)如果出現(xiàn)錯(cuò)誤,fork返回一個(gè)負(fù)值;
一個(gè)進(jìn)程調(diào)用fork()函數(shù)后,系統(tǒng)先給新的進(jìn)程分配資源,例如存儲數(shù)據(jù)和代碼的空間。然后把原來的進(jìn)程的所有值都復(fù)制到新的新進(jìn)程中,只有少數(shù)值與原來的進(jìn)程的值不同。相當(dāng)于克隆了一個(gè)自己。
六、Linux進(jìn)程狀態(tài)
進(jìn)程狀態(tài):
TASK_RUNNING:就緒/可運(yùn)行狀態(tài)
TASK_INTERRUPTABLE:進(jìn)程被掛起(睡眠),直到等待條件為真被喚醒
TASK_UNINTERRUPTABLE:深度睡眠,睡眠期間不響應(yīng)信號
TASK_STOPPED:進(jìn)程的執(zhí)行被暫停
TASK_TRACED:被其它進(jìn)程跟蹤,常用于調(diào)試
EXIT_ZOMBIE:僵死狀態(tài),進(jìn)程的執(zhí)行被終止
EXIT_DEAD:僵死撤銷狀態(tài),防止wait類系統(tǒng)調(diào)用的競爭狀態(tài)發(fā)送
可以使用man ps 查看進(jìn)程狀態(tài) Ss、Sl、S+、Z、I 釋義
具體解釋如下:
- D (TASK_UNINTERRUPTIBLE) 不可中斷的睡眠狀態(tài)
- R (TASK_RUNNING) 正在運(yùn)行,或在隊(duì)列中的進(jìn)程
- S (TASK_INTERRUPTIBLE) ? ? 可中斷的睡眠狀態(tài)
- T (TASK_STOPPED) ? ?停止?fàn)顟B(tài)
- t (TASK_TRACED) 被跟蹤狀態(tài)
- Z (TASK_DEAD - EXIT_ZOMBIE) 退出狀態(tài),但沒被父進(jìn)程收尸,成為僵尸狀態(tài)
- W ? ? ? ? ? ?進(jìn)入內(nèi)存交換(從內(nèi)核2.6開始無效)
- X (TASK_DEAD - EXIT_DEAD) ? 退出狀態(tài),進(jìn)程即將被銷毀
- < ? ?高優(yōu)先級
- N ? ?低優(yōu)先級
- L ? ?有些頁被鎖進(jìn)內(nèi)存
- s ? ?包含子進(jìn)程
- 位于前臺的進(jìn)程組;
- l ? 多線程,克隆線程 ?multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
七、兩種特殊進(jìn)程
7.1 僵尸進(jìn)程
1.僵死狀態(tài)(Zombies)是一個(gè)比較特殊的狀態(tài)。當(dāng)子進(jìn)程退出并且父進(jìn)程(使用wait()系統(tǒng)調(diào)用)沒有讀取到子進(jìn)程退出的返回代碼時(shí)就會產(chǎn)生僵死(尸)進(jìn)程
2.僵死進(jìn)程會以終止?fàn)顟B(tài)保持在進(jìn)程表中,并且會一直在等待父進(jìn)程讀取退出狀態(tài)代碼。
3.所以,只要子進(jìn)程退出,父進(jìn)程還在運(yùn)行,但父進(jìn)程沒有讀取子進(jìn)程狀態(tài),子進(jìn)程進(jìn)入Z狀態(tài)
測試代碼 :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t id = fork();
if (id < 0) {
perror("fork");
return 1;
}
else if (id > 0) { //parent
while(1)
{
printf("parent[%d] is sleeping...,ppid: %d\n", getpid(),getppid());
sleep(1);
}
}
else {
printf("child[%d] is begin Z...,ppid: %d\n", getpid(),getppid());
sleep(5);
exit(1);
}
return 0;
}
fork函數(shù)執(zhí)行后子進(jìn)程PID:15156 在5 s后exit(1)異常退出 ,父進(jìn)程15155沒有讀取到正常的退出代碼導(dǎo)致產(chǎn)生僵尸進(jìn)程。
進(jìn)程PID:15156的名稱加上了【】且后面跟著< defunct > (失效的)
7.2 孤兒進(jìn)程
修改代碼,讓子進(jìn)程和父進(jìn)程同時(shí)不間斷運(yùn)行
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t id = fork();
if (id < 0) {
perror("fork");
return 1;
}
else if (id > 0) { //parent
while(1)
{
printf("parent[%d] is sleeping...,ppid: %d\n", getpid(),getppid());
sleep(1);
}
}
else {
while(1)
{
printf("child[%d] is begin Z...,ppid: %d\n", getpid(),getppid());
sleep(1);
}
}
return 0;
}
運(yùn)行
while :; do ps ajx | head -1 && ps ajx | grep pro_test | grep -v grep ; sleep 1;done
監(jiān)控進(jìn)程狀態(tài)
殺掉父進(jìn)程(10552),子進(jìn)程被編號為1的進(jìn)程接管,該1號進(jìn)程就是bash,而bash就是父進(jìn)程的父進(jìn)程,父進(jìn)程被殺死后,bash進(jìn)程就接管了子進(jìn)程,這種失去“爸爸”后被接管的進(jìn)程就被稱為孤兒進(jìn)程。且子進(jìn)程從前臺進(jìn)程變成了后臺進(jìn)程。
原文鏈接:fork函數(shù)詳解-CSDN博客
【Linux】進(jìn)程周邊001之進(jìn)程概念-CSDN博客
fork()函數(shù)詳解_fork函數(shù)-CSDN博客文章來源:http://www.zghlxwxcb.cn/news/detail-761221.html
原文鏈接:Linux進(jìn)程狀態(tài)_task_interrupt-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-761221.html
到了這里,關(guān)于【Linux】進(jìn)程查看|fork函數(shù)|進(jìn)程狀態(tài)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!