冯诺依曼体系结构
我们常见的计算机,服务器等设备,大部分都遵循冯诺依曼体系。
五大硬件单元:
- 存储器
- 运算器
- 控制器
- 输入设备
- 输出设备
强调:
- 这里的存储器是指内存
- 不考虑缓存情况,这里的cpu只能对内存进行读写操作,不能访问外设
- 外设要输入或者输出数据,也只能写入内存或者从内存中读取
- 一句话:所有设备都只能直接和内存打交道
操作系统:Operator System
概念:
任何计算机都包含了一个基本的程序集合,称为操作系统。笼统理解为,操作系统包括:
- 内核:(进程管理,内存管理,文件管理,驱动管理...)
- 其他程序:(例如库函数,shell程序...)
换句话说,操作系统就是一个计算机上搞管理的软件,对计算机上软硬资源进行管理,让计算机更好使用。
系统调用接口和库函数概念
系统调用接口:就是操作系统内核向上提供的用于访问内核指定功能的接口。
库函数:都系统调用接口进行封装。(在经典场景下。库函数用起来更加方便)
例:printf--格式化打印接口
但其实是系统只提供了一个数据写入文件的接口write
操作系统是怎么管理进行进程管理的呢?--先描述,在组织。
进程
概念:
- 课本上讲,进程就是运行中的程序。
- 站在操作系统上来讲,进程就是系统对运行中程序动态运行的过程,他就是pcb(进程控制块),在liunx下是一个task_struct结构体,系统通过这个描述实现对程序运行的管理以及调度。
task_ struct结构体描述:
标识符,内存指针,上下文数据,程序计数器,进程状态,IO信息等
进程状态:
- 三态模型
- 运行态:进程占有处理器正在运行。
- 就绪态:进程具备运行条件,等待系统分配处理器以便运行。
- 阻塞态:进程不具备运行条件,正在等待某个事件的完成。
- 五态模型
- 运行态-R:正在被执行,以及拿到时间片就可执行的进程。
- 可中断休眠态-S:一种阻塞态。某种运行条件不满足,而暂时不能被调度运行的进程状态,比如
sleep(7);
(小明熬夜写代码,早上不上课,在床前写纸条不让被打扰。纸条就是状态(阻塞)。但老师早上查寝,发现小明没上课在睡觉,将小明叫醒。(中断))
- 不可中断休眠态-D:无法被中断打断,只能等待阻塞条件满足后才能被调度执行。
- 停止态-T:什么都不做(这与休眠不一样,休眠只是阻塞,停止还会被调度。) (小明成植物人了,还活着只是什么都做不了。)
- 僵尸态-Z:进程退出运行,但资源没有完全释放,等待处理的一种状态。
僵尸进程
僵尸进程:处于僵尸态的进程,是一种退出但未完全释放资源的进程。
函数调用完毕后,也会有返回值来对其完成情况加以描述,一个进程退出了,但功能完成情况怎么样呢?这就是进程返回值。也就是说,一个进程死了,他也有死亡原因,其死亡原因就保存在pcb中,
因此,在这个退出的进程的父进程还没处理之前,进程就不能被释放所有资源。只有在他父进程处理之后,也就是获取退出返回值后,才能被释放资源。
来一个创建维持30秒的僵死进程例子
#include<stdio.h> #include<stdlib.h> #include<unistd.h> int main() { pid_t pid = fork(); if (pid < 0) { perror("fork"); return 1; } else if (pid > 0) { printf("parent[%d] is sleeping\n", getpid()); sleep(30); } else { printf("child[%d] is begin \n", getpid()); sleep(5); exit(EXIT_SUCCESS); } return 0; }
创建进程-fork初识
- man fork
- fork有两个返回值
- 父子进程代码共享,数据各自开辟空间(写时拷贝)
fork() creates a new process by duplicating the calling process. The new process, referred to as the child, is an exact duplicate of the calling process, referred to as the parent
函数原型:pid_t fork(void);
头文件:#include <unistd.h>
站在系统角度进程就是pcb,在linux下是task_struck结构体
返回值:父进程的返回值是子进程pid,
在子进程中返回0,失败返回-1。
#include<stdio.h> #include<unistd.h> int main() { printf("Hello Guys!\n"); pid_t pid=fork(); printf("Over!\n"); return 0; }
创建一个进程出来就是创建一个task_struct结构体,也就是创建了一个pcb.
创建一个子进程,也就意味着创建的新的task_struct结构体里大部分的数据都是从父进程pcb中复制过来的(内存指针,上下文数据...)
fork创建子进程后,父子进程谁先运行呢?
答案是不一定,没有固定顺序。
因为我们讲,进程就是pcb,是系统用于程序运行进行调度管理的描述,相当于系统调度到谁,谁就运行。
僵尸进程的危害
僵尸进程的危害:资源泄露
子进程退出后,为了保存退出原因,成为僵尸进程。但如果父进程也退出了,这时,僵尸子进程就失去了存在的意义。
避免:进程等待(等待子进程退出,获取退出子进程的返回值,释放子进程的资源,避免产生僵尸进程)
孤儿进程
孤儿进程:父进程退出后,子进程就成为孤儿进程。
特性:运行在后台,父进程成为1号进程(之前是init进程,现在是systemd)
孤儿进程退出后不会成为僵尸进程。
之前子进程退出后,操作系统会让父进程获取其返回值进行处理,但是父进程并没有处理,导致资源没有被释放。而一旦成为孤儿进程,父进程成为1号进程,一旦子进程退出,就会被立即处理。
思考
- Linux下进程都有哪些状态。
- 不同的状态都表明了什么目的。
- 什么是僵尸进程。
- 僵尸进程有哪些危害。
- 如何避免僵尸进程的产生。
- 什么是孤儿进程,以及其特性。
- 孤儿进程退出后是否会成为僵尸进程。