1、基本概念
1.1 冯诺依曼体系结构
冯诺依曼体系结构对应现代计算器
- 输入设备:键盘
- 输出设备:显示屏、打印机
- 存储器:内存
- 运算器:CPU
- 控制器:南桥北桥
1.2 操作系统
任何计算机系统都包含的一个基本的程序集合,称为操作系统。包含内核(进程管理,内存管理,文件管理,驱动管理)和其他程序。是一款纯正搞管理的软件。
1.3 系统调用和库函数的区别
- 系统调用:操作系统对外表现为一个整体,会暴露自己的部分接口,供上层开发使用,由操作系统提供的接口。
- 库函数:对部分操作系统调用进行适度封装,从而形成库,便于开发。
2、进程
2.1 进程基本概念
表层概念:程序一个执行实例,正在执行的程序
内核观点:担当分配系统资源(CPU,内存)的实体
2.2 进程描述----PCB
进程描述信息会被放在一个叫做进程控制块的数据结构中,理解为进程的属性集合。描述进程的结构体叫做 task_struct
2.3 task_strcut的内容
- 标示符:唯一标示符,用于区别其他进程
- 状态:任务状态,退出代码,退出信息
- 优先级:相对于其他进程的优先级
- 程序计数器:程序中即将被执行的下一条指令的地址
- 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据:程序执行时,寄存器中的数据
- I / O状态信息:包括显示的I/O请求,分配给进程的 I/O 设备和被进程使用的文件列表
- 记账信息:包括处理器时间总和,使用的时钟数总和,时间限制,记账号等
2.4 查看进程的方式
进程的信息在 /proc 系统文件夹中
- ps aux
- ps -elf
- top
ps的命令 | 对应的作用 |
---|---|
-A | 所有进程 |
-a | 在当前环境中运行的进程,不包函环境信息 |
-u | 显示进程用户信息 |
x | 列出系统中所有运行包含tty输出设备 |
f | 显示进程的父子关系 |
e | 显示进程的详细信息 |
3、进程创建----fork
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int ret = fork();
if(ret < 0){
perror("fork");
return 1;
}
else if(ret == 0){
//child
printf("I am child : %d!, ret: %d\n", getpid(), ret);
}else{
//father
printf("I am father : %d!, ret: %d\n", getpid(), ret);
}
sleep(1);
return 0;
}
3.1 进程状态查看
ps aux / ps axj
4、进程状态
- R 运行状态:进程在运行中,或者在运行队列中
- S 睡眠状态:进程在等待时间完成(可中断睡眠)
- D 磁盘休眠状态:不可中断睡眠,这个状态的进程通常会等待IO的结束
- T 停止状态:发送SIGSTOP信号给进程来终止进程。这个被暂停的进程可以通过SIGCONT让进程继续运行
- X 死亡状态:只是一个返回状态,你在任务列表总不会看到
5、僵尸进程
5.1 僵尸进程
当进程退出的时候,父进程没有获取到子进程退出的代码时,就会产生僵尸进程。
注意:
- 如果子进程先结束,父进程还在继续运行,但是并未调用wait/waitpid等待子进程,子进程就会成为僵尸进程。
- 如果父进程先结束,且没有调用wait/waitpid来等待子进程的结束,此时子进程还在运行,父进程已经结束,就并不会产生僵尸进程。
5.2 僵尸进程的危害
- 占用系统资源(PCB需要一直维护数据)
- 内存泄漏
5.3 僵尸进程的解决方法
- 当产生僵尸进程时,即子进程结束了但父进程还在继续运行(并未调用wait/waitpid),假如此时父进程异常终止了,那么该子进程就会自动被init接管。那么它就不再是僵尸进程了。intit回收并释放它所占有的资源。
当然如果进程表越大,init发现它接管僵尸进程这个过程就会变得越慢,所以在init为发现他们之前,僵尸进程依旧消耗着系统的资源
5.4 如何避免僵尸进程
- 如果父进程不是很繁忙,我们就可以通过直接调用wait/waitpid来等待子进程的结束。这会导致父进程被挂起。
- 如果父进程很忙,我们不希望父进程一直被挂起直到子进程的结束。那么我们可以使用信号函数sigaction为SIGCHLD设置wait处理函数。当子进程结束后,父进程就会收到子进程结束的信号,并调用wait回收子进程的资源。
6、孤儿进程
父进程提前退出,子进程被称之为“孤儿进程”
孤儿进程会被1号init进程领养,资源由init回收