1.进程相关概念

程序和进程
并发和并行
进程控制块(PCB) task_struct

/usr/src/linux-headers-5.4.0-26/include/linux/sched.h

进程状态

man 1 ps

图片.png

2.创建进程

2.1 fork

描述: 创建子进程
原型:
#include
#include
pid_t fork(void);

返回值:
成功.父进程返回子进程PID,子进程返回0
失败,返回-1,设置errno值

man 2 fork

2.2 ps kill

man 1 ps ps -ef ps -aux

图片.png
UID: 用户ID
PID: 进程ID
PPID: 父进程ID
C: 进程生命周期中处理器的利用率, 整数值.
STIME: 进程启动时刻
TTY: 进程在哪个终端运行,若与终端无关,则显示?
TIME: 累积使用CPU时间
CMD: 命令名称与参数

图片.pngUSER: 用户名
PID: 进程ID
%CPU: 进程占用CPU百分比
%MEM: 进程占用内存百分比
VSZ: 进程使用虚拟内存量(KB)
RSS: 常驻内存量(KB), 实际使用内存大小
TTY: 进程在哪个终端运行,若与终端无关,则显示?
STAT: 进程状态
START: 进程启动时刻
TIME: 累积使用CPU时间
COMMAND: 命令名称与参数

kill -l kill -9 PID

图片.png

2.3 getpid getppid

3.exec函数族

include
extern char **environ;

int execl(const char pathname, const char arg, …
/ (char ) NULL /);
int execlp(const char
file, const char arg, …
/
(char ) NULL /);
int execle(const char pathname, const char arg, …
/, (char ) NULL, char const envp[] /);
int execv(const char pathname, char const argv[]);
int execvp(const char file, char const argv[]);
int execvpe(const char file, char const argv[], char *const envp[]);

3.1 execl

描述:
原型:
int execl(const char pathname, const char arg, … / (char ) NULL */);

返回值:
成功,则不返回,不再执行execl函数后面的代码.
失败,则返回,执行execl后面的代码,可用perror打印错误原因.

参数:
pathname:待执行程序的绝对或相对路径
arg:起到占位作用,通常写待执行程序名称
…:命令的参数

execl函数一般执行自定义的程序

使用用例
1.execl(“/bin/ls”, “ls”, “-l”, NULL);

3.2 execlp

描述:
原型:
int execlp(const char file, const char arg, … / (char ) NULL */);

返回值:
成功,则不返回,不再执行execl函数后面的代码.
失败,则返回,执行execl后面的代码,可用perror打印错误原因.

参数:
file:待执行命令的名称,根据PATH环境变量搜索该命令; 待执行程序的绝对或相对路径
arg:起到占位作用,通常写待执行程序名称
…:命令的参数

execlp函数一般执行系统自带的程序或命令

使用用例
1.execlp(“ls”, “ls”, “-l”, NULL);
2.execlp(“./server”, “server”, NULL);

4.进程回收

当一个进程退出之后,进程自己能够回收用户空间的自身资源,但不能回收内核空间的自身PCB资源,必须由它的父进程调用wait或waitpid函数完成对子进程的回收,避免资源浪费.

每个进程有且必须有一个父进程

4.1 孤儿进程

父进程先于子进程退出, 则子进程变成孤儿进程.

模拟孤儿进程 [ 代码 ]
孤儿状态 [ 图 ]

孤儿进程会被init进程’领养’,init进程成了孤儿进程的养父进程,当孤儿进程退出之后,由init进程完成对孤儿进程的回收.

4.2 僵尸进程

子进程先于父进程退出. 在子进程退出之后,父进程没有及时调用wait或waitpid函数完成对子进程的回收, 则子进程变成僵尸进程. 即便变成僵尸进程,它的父进程依然是原先的父进程.

模拟僵尸进程 [ 代码 ]
僵尸状态 [ 图 ]

由于僵尸进程是已经结束的进程,不能使用kill命令将其杀死.
通过杀死其父进程的方法可以消除僵尸进程. 杀死父进程之后,僵尸进程会被init进程’领养’, init进程会在后台执行wait或waitpid系统调用完成对僵尸进程的回收. 此乃下下策.
在子进程退出之后,父进程必须及时调用wait或waitpid函数完成对子进程的回收. 此乃上上策.

4.3 wait

描述: 回收子进程
作用:
1.阻塞等待子进程退出
2.回收子进程残留资源
3.获取子进程退出状态

原型:
#include
#include
pid_t wait(int *wstatus);

返回值:
成功,返回子进程ID
失败,返回-1(不再有子进程)

参数:
wstatus: 属于传出参数. 获取子进程退出状态
WIFEXITED(status): =true, 则进程正常结束
WEXITSTATUS(status): 获取进程退出状态
WIFSIGNALED(status): =ture, 则进程异常终止
WTERMSIG(status): 获取进程终止的信号编号

man 2 wait

一次调用只能回收一个子进程

父进程回收子进程 [ 代码 ]

4.4 waitpid

描述:
作用:
同wait函数, 默认阻塞.

原型:
#include
#include
pid_t waitpid(pid_t pid, int *wstatus, int options);

返回值:
成功,返回子进程ID
失败,返回-1(不再有子进程)
成功,返回0 (前提: options=WNOHANG 且子进程正在运行)

参数:
pid=-1,等待任意子进程 (常用)
pid>0,等待指定子进程 (常用)
pid=0,等待与’调用waitpid函数的进程’在同一个进程组的任意子进程.
pid<-1,等待与abs(pid)在同一个进程组的任意子进程.
wstatus: 属于传出参数. 获取子进程退出状态
options:
=WNOHANG,函数非阻塞
=0,函数阻塞

man 2 waitpid

一次调用只能回收一个子进程

父进程回收子进程 [ 代码 ]

4.5 SIGCHLD信号

父进程通过SIGCHLD信号回收子进程

4.6 守护进程

守护进程,即通常所说的Daemon进程,是Linux中的后台服务进程.
周期性地执行某种任务或等待处理某些事件的发生.

UNIX的守护进程一般以*d的形式命名,如httpd,telnetd等等.

守护进程不依赖终端.
从终端开始运行的进程都会依附于运行它的终端,这个终端称为进程的控制终端.
当控制终端被关闭时,相应的进程都会被关闭.比如平常写一个无限循环的进程时,除了使用ctrl+c的方式关闭此进程,就是直接关闭终端,即关闭终端的同时也关闭了进程.但对于守护进程来说,从它开始运行,直到系统关闭才会退出,所以守护进程不能依赖终端.

infuq-zone\重要-操作系统\后台进程.png后台进程.png