进程管理入门

news/2025/3/22 21:26:09/文章来源:https://www.cnblogs.com/codels/p/18787149
  • 进程
    • 常用系统调用介绍
      • getpid() 系统调用
      • getppid() 系统调用
      • fork() 系统调用
    • 查看进程:
      • 方法一: ps 指令
      • 方法二: /proc 目录
    • 进程的状态
      • 运行状态(R状态)
      • 浅度睡眠状态(S状态)
      • 暂停状态(T状态)
      • 深度睡眠状态(D状态)
      • 僵尸状态(Z状态)
    • 特殊进程
      • 僵尸进程
      • 孤儿进程

进程

进程就是在运行的程序,程序是指放在硬盘上的文件。程序首先要加载到内存,CPU才能对它调度执行。

对进程的描述:

使用一个 task_struct 的结构体描述进程,其中包括了进程的主要信息,如进程号,状态等。如此一来,对进程进行操作,就等价于对 task_struct 结构体进行操作。

常用系统调用介绍

getpid() 系统调用

作用:获取当前进程的进程号

示例:

  1 #include <stdio.h>2 #include <sys/types.h>3 #include <unistd.h>4 5 int main(void) {6     pid_t p = getpid();7 8     while (1) {9         printf("This is a process, pid = %d\n", p);10         sleep(1);                                   11     }12 13     return 0;14 }

输出:

[atri@hcss-ecs-d3d5 process]$ ./a.out 
This is a process, pid = 20247
This is a process, pid = 20247
This is a process, pid = 20247

getppid() 系统调用

作用: 获取当前进程的父进程的进程号.

示例:

  1 #include <stdio.h>2 #include <sys/types.h>3 #include <unistd.h>4 5 int main(void) {6     pid_t p = getpid();7     pid_t pp = getppid();8     while (1) {9         printf("This is a process, pid = %d\n", p);10         printf("This is a process, ppid = %d\n", pp);11         sleep(1);12     }13 14     return 0;15 }

输出:

[atri@hcss-ecs-d3d5 process]$ gcc test_getppid.c 
[atri@hcss-ecs-d3d5 process]$ ./a.out 
This is a process, pid = 20637
This is a process, ppid = 18027

fork() 系统调用

作用: 创建子进程.

特性: 调用一次, 返回两次. 在子进程中返回0, 在父进程中返回其 pid

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(void)
{printf("main() progress\n");printf("A. pid of main() is %d\n", getpid());printf("B. parent pid of main() is %d\n", getppid());pid_t son = fork();if (son == 0){printf("This is the sub progress of main()\n");printf("1. The value of getpid() is %d\n", getpid());printf("2. The value of getppid() is %d\n", getppid());}else if (son > 0){printf("This is the value that return in main progress.\n");printf("a. The value of getpid() is %d\n", getpid());printf("b. The value of getppid() is %d\n", getppid());}else {printf("Error!\n");}return 0;
}

输出:

[atri@hcss-ecs-d3d5 process]$ ./a.out 
main() progress
A. pid of main() is 21309
B. parent pid of main() is 18027
This is the value that return in main progress.
a. The value of getpid() is 21309
b. The value of getppid() is 18027
This is the sub progress of main()
1. The value of getpid() is 21310
2. The value of getppid() is 21309
[atri@hcss-ecs-d3d5 process]$ 

难以理解: 这里的If, else if 同时成立, 且同时执行.

查看进程:

方法一: ps 指令

[atri@hcss-ecs-d3d5 ~]$ ps -ajxPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND0     1     1     1 ?           -1 Ss       0   0:12 /usr/lib/systemd/systemd --switched-root --system --deseriali0     2     0     0 ?           -1 S        0   0:00 [kthreadd]2     4     0     0 ?           -1 S<       0   0:00 [kworker/0:0H]2     6     0     0 ?           -1 S        0   0:00 [ksoftirqd/0]2     7     0     0 ?           -1 S        0   0:00 [migration/0]
......
......

字段解释:STAT列中的+表示前台进程组(如S+),无+则为后台进程。TPGID为前台进程组ID,若为-1表示无控制终端。"

技巧:可以用head命令,指定打印表头,再用管道命令配合 grep 命令过滤想查找的进程,如查找 bash 进程:

[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep "bash"PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
18026 18027 18027 18027 pts/0    18248 Ss    1000   0:00 -bash
18027 18249 18248 18027 pts/0    18248 S+    1000   0:00 grep --color=auto bash
[atri@hcss-ecs-d3d5 ~]$ 

方法二: /proc 目录

该目录中以数字命名的目录为进程 id

[atri@hcss-ecs-d3d5 proc]$ ls -al
total 4
dr-xr-xr-x  111 root    root                  0 Feb 22 18:54 .
dr-xr-xr-x.  20 root    root               4096 Feb 28 18:30 ..
dr-xr-xr-x    9 root    root                  0 Feb 22 18:54 1
dr-xr-xr-x    9 root    root                  0 Feb 22 18:54 10
dr-xr-xr-x    9 root    root                  0 Feb 22 18:54 103
dr-xr-xr-x    9 root    root                  0 Feb 22 18:54 11
dr-xr-xr-x    9 postfix postfix               0 Mar  1 14:22 11135
......
......

进程的状态

Linux对状态的定义:

/** 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 *task_state_array[] = {//运行状态"R (running)",		/*  0 *///浅度睡眠状态"S (sleeping)",		/*  1 *///深度睡眠状态"D (disk sleep)",	/*  2 *///暂停状态, 可以重启, 前台变后台R+变R, S+变S"T (stopped)",		/*  4 */"Z (zombie)",		/*  8 */"X (dead)"		/* 16 */
};

运行状态(R状态)

有如下程序:

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

执行时查看进程,为 R+ 状态,即前台运行状态

[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep myprocessPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
23721 26701 26701 23721 pts/0    26701 R+    1000   0:43 ./myprocess
26710 26776 26775 26710 pts/1    26775 S+    1000   0:00 grep --color=auto myprocess

浅度睡眠状态(S状态)

将程序稍作修改,如下:

#include <stdio.h>
int main(void) {int a = 1;while(1) {a++;printf("a = %d\n", a);}return 0;
}

再查看当前进程, 发现是 S+ 状态, 即前台睡眠状态, 因为此时使用了 printf() 函数, 该函数功能是把数据打在屏幕上, 访问了外设, 所以进程一定会在外设准备数据的时候在其阻塞队列中等待, 至于此时进程的状态是静止阻塞(进程数据在磁盘), 还是活动阻塞(进程数据在内存), 这个就看系统的策略了, 不必纠结, 可以理解为 Linux 把状态给封装起来了, 对用户不可见.

该进程的PCB在阻塞队列和运行队列来回跑, 且在阻塞队列中呆得时间长, 因为外设速度更慢, 准备数据需要的时间也比CPU执行打印操作更长.

[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep myprocessPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
23721 27247 27247 23721 pts/0    27247 S+    1000   0:00 ./myprocess
26710 27261 27260 26710 pts/1    27260 S+    1000   0:00 grep --color=auto myprocess
[atri@hcss-ecs-d3d5 ~]$ 

暂停状态(T状态)

在演示暂停状态前, 先补充两个 kill 的信号

使用 kill -l 指令列出其所有可用的信号, 即其对应的数字.

[atri@hcss-ecs-d3d5 process]$ kill -l1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

其中 9) SIGKILL 是终止进程, 19) SIGSTOP 是暂停进程, 18) SIGCONT 是继续执行.

现在再将上面演示 睡眠状态 的进程跑起来, 然后使用 18) SIGCONT19) SIGSTOP 对进程操作, 看看其状态变化.

在该进程向屏幕上打印数据的过程中, 使用了 19) SIGSTOP 指令之后, 可以发现进程的状态变成了 T, 即暂停状态.

[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep myprocessPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
23721 28152 28152 23721 pts/0    28152 S+    1000   0:00 ./myprocess
26710 28161 28160 26710 pts/1    28160 S+    1000   0:00 grep --color=auto myprocess
[atri@hcss-ecs-d3d5 ~]$ kill -19 28152
[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep myprocessPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
23721 28152 28152 23721 pts/0    23721 T     1000   0:00 ./myprocess
26710 28204 28203 26710 pts/1    28203 S+    1000   0:00 grep --color=auto myprocess
[atri@hcss-ecs-d3d5 ~]$ 

此时再用 18) SIGCONT 让进程继续运行, 此时发现, 进程继续执行了, 且原先的 + 消失了, 即此时的进程变成了后台进程:

[atri@hcss-ecs-d3d5 ~]$ kill -18 28152
[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep myprocessPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
23721 28152 28152 23721 pts/0    23721 S     1000   0:00 ./myprocess
26710 28433 28432 26710 pts/1    28432 S+    1000   0:00 grep --color=auto myprocess
[atri@hcss-ecs-d3d5 ~]$ 

此时该进程变成了后台进程, 在启动该进程的shell上, 使用 CTRL + C已经无法退出该进程了, 但该进程还会在这个shell上打印数据, 需要使用kill命令来停止它.

补充: SIGTSTP(Ctrl+Z)可将前台进程挂起为后台停止状态(T), fg 命令可恢复为前台运行.

深度睡眠状态(D状态)

这个状态不是很常见, 简言之, 就是一个特殊的进程(比如用来向磁盘写入重要数据的文件), 给它一个特殊的权限, 操作系统在内存资源不足的时候也不会把它 kill 掉, 以保证数据的完整性. 但, 如果操作系统中堆满了这种进程之后, 就会导致操作系统资源不足, 造成操作系统本身出现问题. 对于这种进程, 除非断电, 或进程自己醒来, 才能结束掉.

例: "执行sync命令强制写盘时, 相关进程可能短暂进入D状态, 此时不可被kill -9终止.


本部分内容等学完进程控制再做修改

僵尸状态(Z状态)

描述:

当进程退出时, 不能立刻释放其对应的资源, 需要等其父进程或操作系统来读取其返回状态, 在这之后才可以释放, 这个结束到释放资源的过程称为僵尸状态.

特殊进程

僵尸进程

描述:

进程已经退出了, 但父进程并没有对其进行回收.

示例: 构造一对父子进程, 待运行后杀掉子进程, 观察子进程的状态.

#include <stdio.h> 
#include <unistd.h>
int main(void) {pid_t p = fork();if (p == 0) {//child;while (1) {printf("child pid = %d\n", getpid());sleep(1);}}else if(p > 0) {//parentwhile (1) {printf("parent pid = %d\n", getpid());sleep(1);}}else {printf("error\n");}return 0;
}

查看进程状态, 并将子进程使用 kill 命令结束, 由于父进程没有做内存回收工作, 所以子进程一直处于待读取的僵尸状态.

[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep my_processPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
25745  3126  3126 25745 pts/0     3126 S+    1000   0:00 ./my_process3126  3127  3126 25745 pts/0     3126 S+    1000   0:00 ./my_process870  3138  3137   870 pts/1     3137 S+    1000   0:00 grep --color=auto my_process
[atri@hcss-ecs-d3d5 ~]$ kill -9 3127
[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep my_processPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
25745  3126  3126 25745 pts/0     3126 S+    1000   0:00 ./my_process3126  3127  3126 25745 pts/0     3126 Z+    1000   0:00 [my_process] <defunct>870  3154  3153   870 pts/1     3153 S+    1000   0:00 grep --color=auto my_process

孤儿进程

描述:

当一个进程的父进程终止运行的时候, 1号进程(操作系统内核) 会领养该进程, 此时该进程称为孤儿进程.

如果进程成为孤儿前是个前台进程, 成为孤儿后会变成后台进程

示例:

有如下程序:

构造一对父子进程, 待运行后在某个时间使用 kill 命令结束父进程, 观察子进程的 ppid 变化情况

#include <stdio.h> 
#include <unistd.h>
int main(void) {pid_t p = fork();if (p == 0) {//child;while (1) {printf("child pid = %d\n", getpid());sleep(1);}}else if(p > 0) {//parentwhile (1) {printf("parent pid = %d\n", getpid());sleep(1);}}else {printf("error\n");}return 0;
}

此时将进程运行起来, 可同时得到父子进程的 pid:

[atri@hcss-ecs-d3d5 lesson13]$ ./my_process 
parent pid = 2224
child pid = 2225
parent pid = 2224
child pid = 2225
......

查看进程信息:

# 此时的父子进程都在运行, 且都是S+状态, 即前台睡眠状态
[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep my_processPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
25745  2224  2224 25745 pts/0     2224 S+    1000   0:00 ./my_process2224  2225  2224 25745 pts/0     2224 S+    1000   0:00 ./my_process870  2290  2289   870 pts/1     2289 S+    1000   0:00 grep --color=auto my_process
# 使用kill命令杀掉父进程后, 子进程2225的ppid从2224变到了1, 
# 此时的子进程就成了孤儿进程被操作系统接管
# 且变成了后台进程
[atri@hcss-ecs-d3d5 ~]$ kill -9 2224
[atri@hcss-ecs-d3d5 ~]$ ps -ajx | head -1 && ps -ajx | grep my_processPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND1  2225  2224 25745 pts/0    25745 S     1000   0:00 ./my_process870  2307  2306   870 pts/1     2306 S+    1000   0:00 grep --color=auto my_process
[atri@hcss-ecs-d3d5 ~]$ 

操作系统为什么要领养孤儿进程?

答: 为了避免该进程变成僵尸进程而占用系统资源.

注意: 使用 kill 命令结束父进程, 父进程没有进入僵尸状态的原因是: 该进程的父进程是 bash 它在它的子进程被 kill 掉的时候会进行状态读取和资源回收.


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/903607.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring 事务失效

场景1:代码:执行结果:异常抛出,但是数据没有回滚。 代理对象调用 b() 方法 没有开启事务:普通对象调用a() 方法开启事务:在b() 方法上加入事务注解,开启事务就没问题:本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/18787133

征程 6X CAMSYS 性能测试方案介绍

1.性能测试方法原理 CAMSYS 其性能指标主要包括:帧率、延迟,以及系统的 DDR 带宽、CPU 占用率等。 对于帧率、延迟,通过在驱动中创建 trace event,分别记录通路上的每个 IP,每帧开始处理(frame_start)和结束处理(frame_end)的时间戳信息和帧信息,来实现帧率计算和延迟…

数据结构2

概率论与数理统计1-基本概念 概率论与数理统计2-基本数据结构 概率论与数理统计3-基本数据处理技术 基本的数据结构 - 数据结构- 数据的逻辑结构- 线性结构- 线性表- 栈(特殊的线性表)- 队列(特殊的线性表)- 字符串- 数组- 广义表- 非线性结构- 树型结构- 图型结构- 数据的存储…

day7 刷牛客华为机试题+学java

https://www.nowcoder.com/exam/oj/ta?page=1&tpId=37&type=37 字符串 第一题:第二题: 省行版:逻辑版:java网课学习: 多态调用成员变量,编译看左边,运行也看左边。调用成员方法时,编译看左边,运行看右边。if(a instanceof Dog d) 导包final 修饰引用类型地址…

【Docker】MySQL、Reids、Mongodb、Nacos、RabitMQ安装指南

1 docker的下载 建议通过 火绒应用商店 或者 联想应用商店 下载 2 配置Docker 配置镜像站 https://docker.1panel.live {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": fa…

Web前端入门第 22 问:CSS 选择器一览

HTML 在语法上并无大小限制,所以其结构可以浩瀚无边,CSS 选择器的作用则是在这些复杂的 HTML 结构中进行元素定位。 示例代码 记住此代码,后面所有的 css 选择器都是基于此代码。 注意:代码中存在两个一样的 id="p1" 元素,仅为了演示效果,正常编码中请保证 id …

曼哈顿距离和切比雪夫距离

曼哈顿距离(Manhattan Distance) 解释:只能横着或竖着走,坐标上两点的距离 假设存在两点 \(A(x_1, y_1)\) \(B(x_2, y_2)\) \(dis(A, B) = |x_1 - x_2| + |y_1 - y_2|\)对于上方求曼哈顿距离的式子,有四种情况 \( \begin{cases} x_1 > x_2 & y_1 > y_2 & {…

如何设置家用威联通 NAS UPS 断电后自动关机并通知其他设备?

场景📝备注: 求轻喷, 求放过. 😅 我真的是个理线方面的白痴. 这已经是我的极限了. 😂我的家庭实验室 Homelab 服务器集群配置如下.上半部分之前已经介绍过了, 这里就不再赘述了. 今天重点介绍介绍 UPS 和 NAS 部分.1台 UPS, 型号为 APC Back-UPS 650. 插座插着: NAS 和 插…

[扫描线] 数据结构测试(2025.3.22)

暴力大赛,赛时暴力打满喜提80pts,可惜T1没想到暴力。 难度:T2<T1<T3.T1 第1题 团队 查看测评数据信息有n个工人,第i个工人的能力是v[i], 他只与能力在L[i]到R[i]之间的人在一起工作,问最多能选出多少人在一起工作。输入格式第一行,一个整数n, 1 <= n <…

centOS 上部署hadoop+mysql+hive 服务之hadoop安装

以下安装的hadoop版本是3.3.6 ,由于hadoop是运行于java环境,因此,需要提前安装java jdk并配置环境变量。 jdk的安装及配置: jdk8 国内下载路径:https://repo.huaweicloud.com/java/jdk/8u202-b08/ 可根据实际需要选择对应的jdk版本 1、下载jdkwget https://repo.huaweicl…

创建django视图和路由

第一个视图 from django.shortcuts import render from django.http import HttpResponse# Create your views here. def hello(request):msg = Hello World!!!return HttpResponse(msg)第一个路由 from django.urls import path from .views import hellourlpatterns = [path(…

8.4.3 基于循环神经网络的字符级语言模型

字符级语言模型的优缺点见下 好处:不用担心\(\left<\text{UNK}\right>\)的出现 坏处:最终的序列要长的多;训练也要复杂得多(对内存和速度的要求都要高得多) 现如今,人们一般使用单词级RNN,但是也有特殊情况会使用字符级RNN 在训练了一个RNN后,我们可以利用这个RN…