进程控制就是系统通过一些具有特定功能的程序来创建进程、 撤销进程以及完成进程各状态间的转换,达到多进程高效率并发执行,从而实现资源共享的目的。
进程创建
创建进程的一般工作
- 分配一个PCB,拷贝父进程的PCB的绝大部分数据
- 给子进程分配资源
- 复制父进程地址空间的数据
- 将进程状态置为就绪态,插入就绪队列
- fork函数 从已存在进程中创建一个新进程,新进程为子进程,而原进程为父进程 父子进程代码共享,数据独有(写时拷贝),运行取决于cpu调度
#include<unistd.h>
pid_t fork(void);
返回值 :- 父进程 : 返回子进程id
- 子进程 : 返回0
- 出错 :返回-1
fork调用失败的原因
- 系统中有太多的进程(内存不够,资源不够)
- 实际用户的进程数超过了限制
进程终止
终止方式:
- main函数中return退出
- exit 库函数
- _exit 系统调用接口
不管哪种退出方式,都会返回一个数字,这个数字是进程的退出状态,表明了进程退出的原因
正常运行完毕,结果符合预期
正常运行完毕,结果不符合预期
异常退出,返回状态将不能作为标准
exit退出
#includ<stdlib.h>
void exit(int status);
status //进程退出状态(原因)
//进程正常终止,退出时会释放所有资源
//调用_exit函数
_exit退出
#include<unistd.h>
void _exit(int status);
status //进程退出状态(原因),父进程通过wait来获取该值
exit与_exit的区别:
- exit是温和性的退出,在退出前会温和的释放资源,刷新缓冲区
- _exit是暴力推出==退出,直接释放资源退出,不会刷新缓冲区
进程等待
一个进程退出之后因为要保存自己退出的原因,因此并不会释放所有的资源,他等着父进程查看他的退出原因,然后释放所有资源,假如父进程根本就没管(比如在做其他事情),那么这个子进程就成了僵尸进程,造成资源泄漏,因此为了防止出现僵尸进程,父进程需要通过进程等待的方式,回收子进程资源,获取子进程退出信息。
进程等待的方式:”
#include<sys/tyoes.h>
#include<sys/whit>
id_t wait(int *status)
pid_t waitpid(pid_t pid,int *status,int options)
//status 输出型参数,获取子进程退出状态(退出状态码),可设置成为NULL(不关心退出状态)
//返回值成功返回子进程的pid,失败返回-1
阻塞:为了完成功能发起调用,如果当前不具备完成条件,则一直等待,直到完成后返回
非阻塞:则立即报错返回
区别:调用功能在当前不具备完成条件是否立即返回
进程的状态
- R 运行态
- S 可中断睡眠态
- D 不可中断睡眠态–磁盘休眠状态
- T 停止状态
- t 追踪状态
- X 死亡状态
- Z 僵尸态
僵尸进程:子进程退出时父进程没有读取子进程退出的状态,就会导致僵尸进程
僵尸进程的危害:
- 父进程如果一直不读取,则子进程一直处于僵尸状态,维护退出状态本身就需要数据维护,所以会存在资源的浪费。
2. 内存泄漏
孤儿进程:父进程先于子进程退出就会产生孤儿进程,它有init进程回收。
杀死进程:
kill
- kill-l 查看信号
- kill pid
- kill -9 强制杀死进程
- kill -进程组id(负号) 杀死一组进程