1.冯·诺依曼体系结构
日常生活照我们常见的计算机,如笔记本,还有我们不常见的计算机,如服务器,大部分都遵循冯·诺依曼体系
,该体系结构示意图如下:
我们所认识的计算机都是由一个个的硬件组组成:
输入单元
:包括键盘、鼠标、扫描仪等输出单元
:显示器、打印机等中央处理器(CPU)
:含义运算器和控制器等
关于冯诺依曼体系,强调:
- 体系中的存储器指
内存
- 不考虑缓存情况,这里的CPU只能对内存进行读写,不能访问外设(输入或输出设备),外设(输入或输出设备)要输入或输出数据,也只能写入内存或从内存中读取,也就是说,
所有设备都只能直接和内存打交道
2.操作系统(Operator System)
概念:任何计算机系统都包含一个基本的程序结构,称为操作系统(OS),其包括:
内核
(进程管理、内存管理、文件管理、驱动管理)其他程序
(如函数库等)
操作系统存在的意义
:
- 与硬件交互,管理所有的软硬件资源
- 为应用程序提供一个良好的执行环境
操作系统的定位:在整个计算机软硬件架构中,操作系统是一款搞管理
的软件。
3.初识进程
查看进程信息
:ls /proc/
* 每个进程都有自己的PID,要获得自己的PID
:getpid() 方法获得父进程的PID
:getppid()方法- Linux下
创建一个子进程
:fork()方法
使用fork创建一个子进程,它的数据和代码是从父进程那里继承过来的,子进程的PCB
大部分内容和父进程一样
父子进程代码共享,数据却各自私有一份(写时拷贝
)
返回值
问题:fork后,子进程返回0,父进程返回子进程的PID(一个父进程有多个子进程,返回PID才能准确锁定)
4.进程状态
R
运行状态(running):进程要么在运行要么在等待队列S
睡眠状态(sleeping):进程在等待事件完成(可中断睡眠)D
磁盘休息状态(Disk sleep):此时进程通常会等待IO的结束(不可中断睡眠)T
停止状态(stopped):通过SIGSTOP信号开暂停运行进程,通过SIGCONT继续运行该进程X
死亡状态(dead):只是一个返回状态,不会出现在任务列表中Z僵尸状态
(zombie):子进程运行终止后,PCB从内存中移除,而他的进程描述符还在,要告知父进程自身状态,这时进程就处于僵尸状态,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息,在 wait 调用之后,僵尸进程就完全从内存中移除。因此一个僵尸存在于其终止到父进程调用 wait等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中,从而会造成内存泄漏
孤儿进程
:父进程如果提前退出,那么子进程就被称为“孤儿进程
”,孤儿进程会被1号init进程领养,当然了,init进程会回收它
5.进程优先级
在Linux或者Unix操作系统中,用ps -l
命令会类似输出一下内容:
修改进程优先级:
nice:启动进程前指定nice值:nice -n -5 ./test
renice:调整已经存在进程的nice:renice -5 -p 5200 //PID为5200的进程nice设为-5
6.环境变量
环境变量:在操作系统中用来指定操作系统运行环境的一些参数
- PATH:指定命令的搜索路径
- HOME:指定用户的主工作目录(用户登录Linux系统时默认的目录)
- ISTSIZE:指保存历史命令记录的条数
- SHELL:当前Shell
查看环境变量
:echo $NAME //NAME:环境变量名称
7.进程的虚拟地址空间
8.进程的创建与终止
8.1.fork函数:pid_t fork(void);
进程调用fork后,内核做:
- 分配新的内存块和内核数据结构给子进程
- 将父进程部分数据结构内容拷贝至子进程
- 添加子进程到系统程序列表中
- fork返回,开始调度器调度
fork返回值
:
- 子进程返回0
- 父进程返回的是子进程PID
fork的写时拷贝
:通常,父子进代码共享,父子在不写入时,数据也是共享的,但是当任意一方视图写入时,便以写时拷贝的方式各自一份副本
fork常规用法:
- 一个父进程希望复制自己,使子进程同时执行不同的代码
- 一个进程要执行不同的程序
fork调用失败
原因:
- 系统中有太多进程
- 实际用户的进程数超过限制
8.2.进程终止
进程的退出场景
:
- 代码运行完毕,结果正确
- 代码运行完毕,结果不正确
- 代码异常终止
进程常见退出方法
:
- 正常终止(可以通过
echo $?
查看进程退出码)
(1)从 main方法返回
(2)调用exit
(3)_exit
- _exit函数:void _exit(int status); //status定义了进程终止状态,父进程通过wait来获取该值
- exit函数:void exit(int status);
exit函数做了如下工作:(1)执行用户通过atexit或on_exit定义的清理函数工作
(2)关闭所有打开的流,所有的缓存数据均被写入
(3)调用_exit
- 异常退出
ctrl + c,信号终止
8.3.进程等待
进程等待的必要性
:
- 子进程退出,如果父进程不管不顾,就可能造成僵尸进程,进程一旦进入僵尸状态那就刀枪不入,杀人不眨眼的“kill -9”也无能为力,毕竟没有谁能够杀掉一个“已经死掉”的进程,那么会进一步造成内存泄漏
- 父进程委派给子进程的任务完成的如何我们也该知道
- 父进程通过进程等待的方式,回收子进程资源,并且获得子进程退出信息
进程等待的方法
:
(1)wait
(2)waitpid
pid_t wait(int* status);
- 返回值:返回被等待进程的PID,失败返回-1
- 参数:输出型参数,获取进程退出状态,不关心则可以设置为NULL
pid_t waitpid(pid_t pid,int* status,int options);- 返回值:(1)当正常返回时waitpid返回收集到的子进程的进程ID
(2)如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0
(3)如果调用中出错则返回-1,这是errno会被设置为相应的值以指示错误的存在- 参数:(1)pid:pid为-1时等待任意一个子进程,与wait等效;pid > 0时,等待其进程ID等于pid的进程
(2)status:WIFEXITED,查看进程是否正常退出,正常退出则为真
WEXITSTATUS,若WIFEXITED非0,提取子进程退出码
(3)options:WNOHANG,若pid指定的子进程没有结束,则waitpai函数返回0不予以等待,若正常结束返回该子进程的ID
- 如果子进程已经退出,调用wait/waitpid时,会立即返回子进程退出信息并释放资源
- 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞
- 如果不存在该子进程,则立即出错返回
获取子进程status
- wait和waitpai方法都有一个status参数,该参数是一个输出型参数,由操作系统来填充
- 如果传递NULL,表示不关心子进程的退出状态信息
- 否则操作系统会根据该参数,将子进程的退出信息返回给父进程
- status不能简单的当做整型来看,可以当做位图来看待,具体细节如下图: