进程
1.进程在操作系统中叫做 PCB (进程控制块)
2.在linux下是用task_struct这样的结构以保存的,所有进程信息都以task_struct结构体在内核中以链表的形式存储。(它会被加载的内存当中并且包含着进程的信息)
task_struct
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。 其他信息
查看进程
ls /proc (存放着所有进程的信息)
例如要查看某一个pid为 1 进程信息:ls /proc/1
大多数进程同样可以用 top 和 ps 查看
通过系统调用获取进程标识符
int pid =getpid();
通过系统调用创建进程-fork
- fork存在两个返回值
- 父子代码共享,数据各自开辟空间,私有一份(采用写时拷贝)-----当共享代码中数据需要改变时,系统会重新为子进程开辟一份空间。
vfork:
存在的意义是为了快速创建子进程,并且子进程是专门用来运行其他程序的。共用地址空间可以减少子进程的数据拷贝。但在fork实现了写诗拷贝技术之后就淘汰了
深入理解代码共享数据独有
以代码为例子:
我们很容易看到为什么地址相同但是val值却不同,因为在操作系统使用的时虚拟内存,它被描述在一个叫mm_struct结构体其中,也叫内存指针,同样是我门task_struct结构体中的一员,因为fork采用写时拷贝技术,所以在拷之后改变里虚拟内存和物理内存的映射关系。
进程状态查看
ps aux/ef/axj 命令
僵尸进程:
原因:先于父进程退出,所以操作系统为了防止数据丢失,而没有释放内存。
代码演示
在一个终端执行./zombie
在另一个终端输入一下命令:
孤儿进程:
原因:父进程先于子进程退出。
进程优先级:
原因:让操作系统运行的更加合理。
查看进程优先级:ps -l PRI NI PRI(新)=PRI(旧)+NI
I/O密集型:时指系统资源被I/O读写占用,cpu利用率低。
cpu密集型:cpu正在与内存硬盘进行数据计算和逻辑判断,这个时候资源使用率较高。
PRI 和NI
renice -n(NI_val) -p pid
nice -n(NI_val) ./file
nice值得范围:-20~19(进程优先级辅助参数,可以调整优先级)
进程终止
终止场景:进程退出返回值得作用
正常退出:结果符合预期
正常退出:结果不符合预期
异常退出
终止方式:
main 函数中return
exit() 库函数 (推出前刷新缓冲区)
-exit() 系统调用接口 直接退出,释放资源
返回值:查看进程返回值用 echo &? 查看
错误编号:每一个系统调用都会重置进程中errno这么一个全局变量,这个全局变量中存储的就是当次调用系统接口的错误编号 ,当系统调用出错的时候,用户就可以通过errno获取系统调用错误的原因
进程等待
为了避免子进程成为僵尸进程
阻塞:为了完成某一项功能而发起调用,如果当前不具备完成条件,则一直等待,直到完成后返回
非阻塞:为完成功能而发起调用,如果当前不具备条件则立即报错返回
wait():
- status:用于获取退出原因
- 如果正常返回为任意子进程的pid,否则返回失败为 -1(没有子进程)
- wait(NULL)不关心子进程的状态
waitpid():
- status:用于获取退出原因
- pid > 0 等待指定子进程退出(pid和子进程的pid相等) pid == -1 等待任意子进程退出
- options :是否设置阻塞或者非阻塞 WNOHANG(设置非阻塞)
status的计算