个人主页:chian-ocean
文章专栏-Linux
前言
进程是现代操作系统中一个不可或缺的概念,其主要目的在于管理资源、实现并发、提高系统效率,并确保系统的稳定性和安全性。
进程的定义
进程(Process) 是计算机操作系统中的一个基本概念,指的是一个正在运行的程序的实例。它是程序在计算机中执行的动态表现,不仅包含程序的代码(即可执行指令),还包括程序在运行时所需的各种资源,如内存、文件句柄、CPU时间等。
- 在理解操作系统的时候,OS是一个进行软硬件管理的软件。
- 进程通俗的理解就是一个被加载到内存的程序(进程也叫任务)
OS如何管理进程
在理解操作系统的时候提出来 ,OS进行管理是 先描述,后组织。
- 任何一个进程在被加载在内存的时候形成一个一个进程,这时候操作OS进行描述的过程。
PCB
PCB的理解
学校在对一个人管理学生的时候需要记录一个人的基本信息(是所有学生所共有的特征)有,姓名、身高、体重、身份证等等。OS引入了PCB(Process Ctrl Block)进程控制块:进程属性的集合(也就是描述的过程)
- 进程控制块(Process Control Block, PCB)是操作系统中用于描述和控制一个进程的最重要的数据结构。
- 可以把PCB理解为一个进程的“身份证”,它包含了操作系统对每个进程管理和调度所需要的所有信息。
- 当一个程序被创建并执行时,操作系统就为它创建一个PCB,用来追踪和管理它的状态。
PCB的内容
PCB
的本质就是结构体(struct),里面储存了各种各样的信息,例如:
- 进程标识信息:进程ID(PID),父进程ID(PPID),用于唯一标识进程和维护进程关系。
- 进程状态:描述当前进程的状态,如就绪、运行、阻塞等。
- CPU寄存器和程序计数器:保存当前的CPU状态,以便进行上下文切换。
- 内存管理信息:如页表、段表,用于描述进程的内存空间。
- 调度信息:包括进程优先级、时间片等,用于进程调度。
- 资源信息:记录进程打开的文件描述符和使用的I/O设备。
通俗的讲:进程控制块(PCB,Process Control Block)本质上是一个数据结构,它是操作系统用来描述、管理和控制一个进程的所有关键信息的集合
形象的表述为
# 进程 = PCB(内核操作系统数据结构) + 自己数据代码
通过复杂的数据结构相互联系,形成有序的属性集合的连接(组织的过程)
Linux系统下进程的管理
上述说OS是通过PCB进行进程的管理,在Linux
下的PCB是tast_struct
(tast_struct
是PCB的一种),Linux
下管理为2点
Linux
系统下通过task_struct
进行属性的描述。Linux
系统下本质是通过双链表进行连接,进而达到OS对进程的管理
查看正在跑的进程:
特别说明:
- CWD(Current Working Directory),即当前工作目录
- exe是你正在执行的文件
CWD的作用
- 文件路径解析:在操作文件时,如果给定的路径是相对路径,那么相对路径就是基于当前工作目录进行解析的。例如,如果当前工作目录是
/home/user
,而你输入命令cat example.txt
,系统会寻找/home/user/example.txt
这个文件。
查看标识符
# 输入:
ps ajx | head -1 ; ps ajx | grep 18549
看向第二行:
-
**PID(Process Identifier,进程标识符)**是操作系统分配给每个正在运行的进程的一个唯一标识符,用于区分不同的进程。
-
PPID(Parent Process Identifier) 是操作系统中用于标识一个进程的父进程的标识符。每个进程都有一个PID(Process ID),此外也有一个PPID,它用来表示该进程是由哪个进程创建的。
# 我们过滤信息,为什么会出现这一行
17986 18592 18591 17986 pts/1 18591 S+ 1000 0:00 grep --color=auto 18549
# 我们在过滤信息的通过`grep`, 这个也是个进程,所以在查看进程时过滤信息时候,grep也存在。
通过系统调用可以调用到获得PID和PPID
1 #include<iostream>
2 #include <unistd.h>
3 #include<sys/types.h>
4 using namespace std;
5
6 int main()
7 {
8 while(true)
9 {
10 cout << "进程id:"<< getpid() <<endl; // 调用PID
11 cout << "进程pid:"<< getppid() <<endl; // 调用PPID
12 sleep(3);
13 }
14 return 0;
15 }
执行结果:
ps ajx | head -1 ; ps ajx | grep 19038
bash
的PID是process
的PPIDbash
是process
的父进程,二者构成父子进程
通过系统调用创建进程
fork()介绍
fork()
是操作系统中的一个关键系统调用,用于在运行的进程中创建一个新的进程。它最常用于Unix和Linux操作系统中,通过调用fork()
,一个现有的进程可以复制出一个新进程。被创建的新进程被称为子进程(Child Process),而调用fork()
的原始进程被称为父进程(Parent Process)。
fork() 的返回值
fork()
系统调用的返回值非常重要,因为它可以帮助进程分辨自己是父进程还是子进程。
- 父进程中返回子进程的 PID:在父进程中,
fork()
的返回值是子进程的 PID(一个正整数),这意味着父进程可以知道新创建的子进程的进程标识符。 - 子进程中返回 0:在子进程中,
fork()
的返回值为0,这意味着子进程可以识别自己是由fork()
产生的副本。 - 错误返回值 -1:如果
fork()
调用失败,例如系统资源不足时,它会返回 -1,表示进程创建失败。此时,通常需要进行错误处理。
# 执行代码
#include<iostream>
2 #include <unistd.h>
3 #include<sys/types.h>
4 using namespace std;
5
6
7 int main()
8 {
9 pid_t id = fork();
10
11 if(id == 0)
12 {
13 while(true)
14 {
15 cout<<"子进程:"<< id << endl;
16 sleep(5);
17 }
18 }
19 else if(id > 0)
20 {
21 while(true)
22 {
23 cout<<"父进程:"<< id << endl;
24 sleep(5);
35 return 0;
36 }
查看进程:
# 执行 每3秒刷新一下进程
while : ; do ps axj | head -1 && ps axj | grep process | grep -v grep ; sleep 3 ;done
-
- 两个
process
上面进程 PID 23296 下面进程的PPID是 23296
- 两个
- 父子进程和的
PID
是 21346
当 fork()
被调用时,操作系统会:
-
操作系统创建一个新进程(子进程),并复制父进程的地址空间。此时父子进程的地址空间是独立的,但内容完全相同。
-
虽然父子进程的地址空间是复制的,但现代操作系统通常使用**写时复制(Copy-on-Write)**优化。即只有在进程修改数据时,才真正复制内存。
-
两个独立的进程在同时独立运行实现了返回值的不同,这就是为什么出现两个返回值。
如何实现区分:
-
操作系统在内核中维护进程表。当
fork()
被调用时,系统为子进程分配一个新的进程表项(即子进程的 PID)。 -
根据系统调用的上下文,内核可以清楚地知道当前执行的是父进程还是子进程,并返回相应的值。
-
上述代码在fork返回值的不同进程之间,数据发生了写时复制通过调用系统上下文对返回值进行确定。
什么出现两个返回值。
如何实现区分:
-
操作系统在内核中维护进程表。当
fork()
被调用时,系统为子进程分配一个新的进程表项(即子进程的 PID)。 -
根据系统调用的上下文,内核可以清楚地知道当前执行的是父进程还是子进程,并返回相应的值。
-
上述代码在fork返回值的不同进程之间,数据发生了写时复制通过调用系统上下文对返回值进行确定。