一.进程的含义
进程是一个程序执行的过程,会去分配内存资源,cpu的调度。
pcb(process control block):进程控制块是一个结构体。
PID:进程标识符。
二.进程和程序的区别
程序:静态。存储在硬盘中代码,数据的集合。
进程:动态。程序执行的过程,包括进程的创建,调度,消亡。
.c------>a.out------>process(pid)
1)程序是永存的,进程是暂时的。
2)进程有程序状态的变化,程序没有。
3)进程可以并发,程序无并发。
4)进程与进程会存在竞争计算机的资源。
5)一个程序可以运行多次,变成多个进程;一个进程可以运行一个或多个程序。
6)内存分布:进程的空间是0~3G,内核的空间是3~4G
三.进程分类
1.交互式进程
与用户直接交互的进程。
2.批处理进程 shell脚本
执行一系列预定义任务的进程。
3.守护进程
在后台运行,为系统提供服务的进程。
四. 进程的作用
- 进程的作用:实现资源的并发和并行使用。
- 并发:多个进程在宏观上同时进行。
- 并行:多个进程在微观上同时进行。
五. 进程的状态
- 基本状态:就绪、执行、阻塞(等待、睡眠)。
- Linux中的进程状态:运行、睡眠、僵尸、暂停。
六. 进程的调度和上下文切换
- 进程调度是内核的主要功能之一。
- 调度算法:时间片轮转(RR)、先进先出(FIFO)等。
七. 查询进程相关命令
-
ps aux
:查看进程相关信息
1.就绪态、运行态 R
2.睡眠态、等待态
可唤醒等待态 S
不可唤醒等待态 D
3.停止态 T
4.僵尸态 Z
5.结束态
-
top
:根据CPU占用率查看进程信息
-
kill
和killall
:发送信号给进程
1.kill -2 PID 15
发送信号+PID对应的进程,默认接收者关闭
2.killall -9 进程名
发送信号 进程名对应的所有进程
killall a.out
八. 进程系统调用
1.pid_t fork();叉子
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
// fork失败
perror("fork failed");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程
printf("I am the child process, my PID is %d\n", getpid());
} else {
// 父进程
printf("I am the parent process, my PID is %d, and the child PID is %d\n", getpid(), pid);
}
return 0;
}
- 一次调用,两次返回:
fork()
在父进程中返回子进程的 PID,在子进程中返回 0。 - 执行顺序不确定:子进程和父进程的执行顺序是不确定的,具体哪个先执行取决于操作系统的调度策略。
- 变量不共享:在
fork()
调用时,子进程获得父进程数据空间的副本,但两个进程的变量是独立的,对一个进程中的变量所做的更改不会影响另一个进程。 - 子进程复制:子进程复制父进程的用户空间(0到3GB),以及父进程的进程控制块(PCB),但两者拥有不同的 PID。
- 功能:
fork()
用于克隆当前进程,创建一个同名的新进程,即子进程。子进程是父进程的完全拷贝,但它们是两个独立的进程,拥有自己的执行环境和资源。
返回值:
- 父进程中:成功时返回子进程的 PID(一个大于 0 的整数),失败时返回 -1,并设置
errno
以指示错误。 - 子进程中:成功时返回 0,失败时不会执行(因为子进程的创建失败,
fork()
不会返回)。
2.pid_t getpid(void);
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid = getpid(); // 获取当前进程的 PID
printf("Current process PID: %d\n", pid);
return 0;
}
- 原型:
pid_t getpid(void);
- 功能: 获取调用该函数的进程的进程标识符(PID)。
- 参数: 无(缺省)。
- 返回值: 当前进程的 PID。
3.pid_t getppid(void);
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t parent_pid = getppid(); // 获取父进程的 PID
printf("Parent process PID: %d\n", parent_pid);
return 0;
}
- 原型:
pid_t getppid(void);
- 功能: 获取调用该函数的进程的父进程的 PID。
- 参数: 无(缺省)。
- 返回值: 调用进程的父进程的 PID。
4.fork() && fork() || fork();表达式分析
fork() && fork()
: 首先调用fork()
,然后在父进程中根据第一次fork()
的结果决定是否执行第二次fork()
。如果第一次fork()
成功,会创建一个新的子进程,然后在父进程中执行第二次fork()
,可能再创建一个子进程。如果第一次fork()
失败,整个表达式失败,不会执行第二次fork()
。fork() || fork()
: 首先调用fork()
,如果失败,则执行第二个fork()
。如果第一个fork()
成功,整个表达式成功,不会执行第二个fork()
。
5.面试题解答
面试题解答
-
一次
一次fork()
生成几个进程?fork()
调用生成两个进程:一个父进程和一个新的子进程。 -
他们之间的关系是什么样的?
子进程是父进程的副本,拥有自己的 PID,但它继承了父进程的用户空间、打开的文件描述符、信号处理等。 -
如果两次
如果在父进程中连续执行两次fork()
同时(或连续)执行,会生成几个进程?他们之间的关系如何表示?fork()
,将生成三个进程:原始的父进程、第一个子进程和第二个子进程(孙进程)。他们可以表示为一个树状结构,原始父进程是树的根,第一个子进程是根的子节点,第二个子进程(孙进程)是第一个子进程的子节点。