前言
进程是分配系统资源的基本单位
linux的进程与Windows的一样使用的是虚拟内存,而Linux虚拟地址到物理地址的转换是通过MMU(分页内存管理单元)实现的。用户空间映射到物理内存是独立的。
那么系统是如何管理进程的呢?
进程控制块(PCB)是系统为了管理进程设置的一个专门的数据结构。系统用它来记录进程的外部特征,描述进程的运动变化过程。同时,系统可以利用PCB来控制和管理进程,所以说,PCB(进程控制块)是系统感知进程存在的唯一标志。
说白话就是每个进程都有一个PCB结构体来管理进程
使用grep查找PCB结构体
sudo grep -rn "struct task_struct {" /usr/
光标停留在{上,按% ,可以到结构体的结尾。400多行,由于此结构体太大我就不贴出来了。只选取一些关键的成员看看
- 进程id。系统中每个进程有唯一的id,在C语言中用pid_t类型表示,其实就是一个非负整数。* 进程的状态,有就绪、运行、挂起、停止等状态。
- 进程切换时需要保存和恢复的一些CPU寄存器。* 描述虚拟地址空间的信息。* 描述控制终端的信息。
- 当前工作目录(Current Working Directory)。
- umask掩码。
- 文件描述符表,包含很多指向file结构体的指针。
- 和信号相关的信息。
- 用户id和组id* 会话(Session)和进程组。
- 进程可以使用的资源上限(Resource Limit)
进程相关API
创建一个新的子进程
pid_t fork(void);
返回值:
- 失败-1
- 成功,两次返回
父进程返回子进程的id
子进程返回0
获得当前进程pid
pid_t getpid(void);
获得当前进程父进程的id
pid_t getppid(void);
父子进程
init进程是所有进程的祖先
查看进程
ps
- psaux
- psajx --可以追述进程之间的血缘关系
杀死进程命令
kill
- kill-l 查看信号相关的信息
- 给进程发送一个信号
- SIGKILL9号信号
- kill-SIGKILL pid --杀死进程
exec族函数
exec族函数换核不换壳,将其代码考到原先进程的代码块中,并没有开启新的进程
执行其他程序,需要加路径
int execl(const char *path, const char arg, ... / (char *) NULL */);
执行程序的时候,使用PATH环境变量,执行的程序可以不用加路径
int execlp(const char *file, const char arg, .../ (char *) NULL */);
- file 要执行的程序
- arg 参数列表(参数列表最后需要一个NULL作为结尾,哨兵)
-
返回值 只有失败才返回
image.png
孤儿进程与僵尸进程
孤儿进程:父亲死了,子进程被init进程领养。
僵尸进程:子进程死了,父进程没有回收子进程的资源(PCB)
如何回收僵尸进程:杀死父亲,init领养,负责回收。
子进程回收
回收子进程,知道子进程的死亡原因
pid_t wait(int *status);
作用:
- 阻塞等待
- 回收子进程资源
- 查看死亡原因
参数:
- status 传出参数
返回值:
- 成功返回终止的子进程ID
- 失败返回-1
子进程的死亡原因:
- 正常死亡WIFEXITED(如果WIFEXITED为真,使用WEXITSTATUS得到退出状态)
- 非正常死亡WIFSIGNALED(如果WIFSIGNALED为真,使用WTERMSIG得到信号)
回收子进程,可不阻塞
pid_t waitpid(pid_t pid, int *status, int options);
参数:
- pid
<-1 -组id
-1 回收任意
0 回收和调用进程组id相同组内的子进程
>0 回收指定的pid - options
0 与wait相同,也会阻塞
WNOHANG 如果当前没有子进程退出的,会立刻返回
返回值:
- 如果设置了WNOHANG,那么如果没有子进程退出,返回0
如果有子进程退出,返回退出的pid - 失败返回-1(没有子进程)
网友评论