文章目录
进程属性
进程属性保存在进程控制块中(PCB)
内核为每个进程维护了一个PCB用于管理相应进程的信息
标识符
进程标识符
即进程id,简称pid
通常为前一个pid加一,因为pid取值范围有限,若已是最大值,则需要创建的下一个pid必须使用闲置的数值
父进程标识符
ppid
创建该进程的进程所对应的id
编号1位init进程,除了它没有,其他都有
用户标识符
uid
创建这个进程的用户
组标识符
创建进程的用户所属的组,gid
进程函数接口
标识符 | 函数接口 |
---|---|
pid/ ppid | pid_t getpid(void) / pid_t getppid(void) |
uid/ euid | uid_t getuid(void) / uid_t geteuid(void) |
gid / egid | gid_t getgid(void) / gid_t getegid(void) |
进程状态
初始态、就绪态、运行态、睡眠态、终止态
就绪态
所需资源分配到位,等待CPU状态
运行态
此状态的进程数目必定小于等于处理器的数目,即每个CPU上至多能运行一个进程
睡眠态
分为可中断的睡眠和不可中断的睡眠
不可中断睡眠:由外部I/O调用等造成的睡眠
可中断睡眠:进程当前对应用户请求已经处理完毕,暂时退出CPU,当再次发出请求时,可随时可被唤醒
终止态
进程运行完毕,不会被调度,不会占用CPU
寄存器信息
存储中断信息,以便从中断位置继续向下执行
页表指针
程序运行时,系统会为其开辟一段4G的虚拟内存,大部分用于存放代码段、数据段等信息。当虚拟内存与物理内存相映射时,各个虚拟内存中地址相同的数据会被MMU(内存管理单元)映射到内存中不同的物理地址
Linux采用分页存储的方式管理内存。操作系统使用页表来存储这个逻辑地址和物理地址的对应关系,每一个进程的PCB都有一个指向页表的指针。
进程组与会话
用户启动了一个进程为实现功能所需的附加进程视为同一个进程组,用户启动的进程即为进程组的领导进程,id也是是被进程组的进程组id即pgid
会话是进程组的集合,每个进程组被称为一个工作job
会话的意义在于可同一个终端执行多个进程组
进程控制
创建进程
创建一个
fork
函数是实现多任务系统管理的基础,在unistd.h
库中
pid_t fork(void)
调用fork函数创建的进程称为子进程,调用fork函数的称为父进程
调用后作用是复制一个进程,父子都会往下进行
父进程放回子进程的id,子进程返回0,错误返回-1
程序编程两份
一般来说,fork后父子执行顺序是不确定的
创建多个
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
pid_t pid;
int i;
for (i = 0; i < 5; i++){
if((pid = fork()) == 0) // 如果是子进程跳出循环
break;
}
if(pid == -1){
printf("fork error");
exit(1);
}
else if(pid > 0){
printf("parents porcess: pid = %d\n", getpid());
}
else if(pid == 0){
printf("child num = %d , pid = %d\n", i + 1, getpid());
}
return 0;
}
exec函数族
功能:找到指定的文件夹或路径找到可执行文件,用该文件取代调用该函数的进程中的程序,再从该文件的main()函数开始执行文件的内容
调用exec函数族不会创建新进程,exec只是用新程序中的数据替换了进程中的代码段、数据段、以及堆和栈中的数据
#include <unistd.h>
int execl(const char *pathname, const char *arg, ...);
int execlp(const char *filename, const char *arg, ...);
int execle(const char *pathname, const char *arg, ..., char *const envp[]);
int execv(const char *pathname, char *const argv[]);
int execvp(const char *filename, char *const argv[]);
int execve(const char *pathname, char *const argv[], char *const envp[]);
解析exec函数族
- 末尾带p的,需要使用文件名,即使用file作为参数,参数中包含/就将其视为路径名,否则系统就根据进程的环境变量中指定的各个目录中搜索传入的文件;当末尾不带p的,就需要使用路径名了
- execl开头的需要以列举的方式给出参数,最后要用NULL代表参数截止;exev开头的将通过向量表来进行传参,在向量表(v就代表的悲催先系统)中的参数最后一个也要是NULL
- 对于以
e
(表示environment
)结尾的exec函数,可以把一份新的环境变量表传给它,其他exec函数仍使用当前的环境变量表执行新程序。
实际上只有execve是真正的系统调用
执行ls命令
#include <unistd.h>
int main(){
execl("/bin/ls", "-a", "-l", "test_fork.c", NULL);
execlp("ls", "-a", "-l", "test_fork.c", NULL); // 参数
char *arg[] = {"-a", "-l", "test_fork.c", NULL};
execvp("ls", arg);
execv("ls", arg);
perror("error")
}
调用不成功的概率比较大,因此在调用玩后使用perror()函数来打印错误信息
进程退出
exit()
在系统库stdlib.h
0表示正常退出,非0表示异常退出
进程同步
把异步环境下的一组并发进程因相互制约而互相发送信息、互相合作、互相等待,使得各进程按一定的速度和顺序执行称为进程间的同步
wait()
存在与系统库中sys/wait.h
中
pid_t wait(int * statue)
调用wait()函数会被挂起,进入阻塞态,直到子进程变为僵尸态,wait函数捕获到该进程的退出信息时才会转为运行态,回收子进程资源并返回;若没有将会一直阻塞。
若当前进程有多个子进程,只要捕获一个变为僵尸态的子进程的信息,wait()就会返回并使进程恢复执行。
参数中的指针用来保存退出时的状态信息,通常不需要在意,可直接设为NULL
若调用成功,返回子进程的进程id;若调用失败,wait返回-1,errno设为ECHILD
waitpid()
waitpid(pid_t pid, int status, int options)
pid的不同取值对于函数来说有不同的作用
- pid > 0 只等待pid与该参数相同的进程,若进程退出,则函数就会返回;否则会一直等待
- pid=-1 与wait函数相同,将阻塞等待并回收一个子进程
- pid = 0 会等待同一个进程组的所有子进程,若子进程进入了其他进程组,则waitpid不再关心它的状态
- pid < -1 会等待指定进程组中的任何子进程,进程组的id为pid 的绝对值
option提供控制进程组中的任何子进程,是一个常量或由|连接的两个常量,支持如下:
- WNOHANG。即使子进程没有终止,waitpid也会立即返回,即不会使父进程阻塞
- WUNTRACED。如果子进程暂停执行,则立即返回
- 如果不想使用该参数,设为0
返回值会出现三种情况:
- 正常返回时,返回捕捉到的子进程的pid
- option设置为WNOHANG,但调用waitpid时发现没有已退出的子进程可以收集,则返回0
- 若调用出错,返回-1,。error会设置为相应的值以指示错误位置
进程管理命令
ps
查看当前正在运行的进程
- a 显示终端机下所有的进程,包括其他用户启动的进程
- u 以用户的形式展现系统中进程
- x 忽视终端机,显示所有进程
- e 显示每个进程使用的环境变量
- r 只列出当前终端机正在执行的进程
注意au属性的输出信息
top
动态的显示进程信息
默认间隔时间为3s
对于上面5行,可以通过热键l、t、m来控制
可使用-d参数自定义刷新间隔;-b批处理3s滚一次,-n控制循环显示次数
运行top命令之后,如果想退出该命令,键入q即可或按ctrl c
pstree
以树状图的形式展示,直接观察进程间的派生关系
- -a 显示每个进程的完整命令
- -c 不使用精简标识法
- -h 列出树状图,特别标明正在执行的
- -u 显示用户名称
- -n 使用程序识别码来排序
pgrep
根据进程明聪进程队列中查找进程,成功后默认显示进程的pid
通过命令缩小搜索范围:
- -o 仅显示同名进程中pid最小的
- -n 仅显示同名进程中pid最大的
- -p 指定父进程的pid
- -t 指定开启的终端
- -u 指定进程的有效用户id
nice
专门用来更改优先级的命令
使用-n选项来表示优先级,
nice -n 5 bash
bg fg
前台命令:执行过程中输出信息会逐条输出到屏幕,或命令打开的内容会替代原来的终端命令
后台命令:命令执行后,不占用命令提示符,用户可继续在终端中输入命令,执行其他操作的命令
bg fg使进程在前台和后台执行切换
bg讲进程放在后台
bg 参数
也可以在命令后追加&,在进程创建的时候直接调入后台执行
command &
使用ctrl Z
调入后台,但调入后台的进程会被暂时停止
fg
与bg
相反
fg 作业号
jobs
前台命令按下Ctrl Z
,这是一个状态信息,1表示作业号,stopped表示进程现在停止
使用jobs命令可以查看Linux中的作业列表和作业状态。
- -l 显示进程号
- -p 仅显示作业对应的进程号
- -n 显示作业状态的变化
- -r 仅显示运行状态的任务
- -s 仅显示停止状态的任务
参数为作业号,用于显示某个作业的信息
kill
终止正在运行的进程
trl Z`调入后台,但调入后台的进程会被暂时停止
fg
与bg
相反
fg 作业号