1.进程相关概念
程序和进程
并发和并行
进程控制块(PCB) task_struct
/usr/src/linux-headers-5.4.0-26/include/linux/sched.h
进程状态
man 1 ps
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
UID: 用户ID
PID: 进程ID
PPID: 父进程ID
C: 进程生命周期中处理器的利用率, 整数值.
STIME: 进程启动时刻
TTY: 进程在哪个终端运行,若与终端无关,则显示?
TIME: 累积使用CPU时间
CMD: 命令名称与参数
USER: 用户名
PID: 进程ID
%CPU: 进程占用CPU百分比
%MEM: 进程占用内存百分比
VSZ: 进程使用虚拟内存量(KB)
RSS: 常驻内存量(KB), 实际使用内存大小
TTY: 进程在哪个终端运行,若与终端无关,则显示?
STAT: 进程状态
START: 进程启动时刻
TIME: 累积使用CPU时间
COMMAND: 命令名称与参数
kill -l kill -9 PID
2.3 getpid getppid
3.exec函数族
include
extern char **environ;
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信号
4.6 守护进程
守护进程,即通常所说的Daemon进程,是Linux中的后台服务进程.
周期性地执行某种任务或等待处理某些事件的发生.
UNIX的守护进程一般以*d的形式命名,如httpd,telnetd等等.
守护进程不依赖终端.
从终端开始运行的进程都会依附于运行它的终端,这个终端称为进程的控制终端.
当控制终端被关闭时,相应的进程都会被关闭.比如平常写一个无限循环的进程时,除了使用ctrl+c的方式关闭此进程,就是直接关闭终端,即关闭终端的同时也关闭了进程.但对于守护进程来说,从它开始运行,直到系统关闭才会退出,所以守护进程不能依赖终端.
infuq-zone\重要-操作系统\后台进程.png