冯诺依曼体系结构
-
结构决定算法
-
输入设备 -- 存储器( 内存 ) -- 输出设备
-
中央处理器 , ( 运算器 , 控制器 )
-
在数据层面上CPU只能和内存打交道 , 外设不能直接和CPU沟通 , ( 所有设备只能直接和内存打交道 )
操作系统
-
操作系统是一个搞管理的软件 ( 提供更好的执行环境 )
-
操作系统是一个完整的系统 , 要使用其功能必须以接口的形式使用 将操作系统的接口调用称为系统调用
-
计算机管理硬件 1.描述起来 ,用struct结构体 2.组织起来,用链表或者其他更高效的数据结构
系统调用和库函数
-
使用shell外壳 ,lib,部分指令对系统调用进行适度封装,从而形成了库,有利于上层用户或开发者进行二次开发
扫描二维码关注公众号,回复: 3570286 查看本文章
进程基本概念 (先描述后组织)
描述进程--PCB ( PCB里包含了进程的所有信息 )
-
Linux操作系统下PCB为 : task_struct
-
(重要) 如何查看 PID 查看系统进程状态ps aux、ps axj , ps aux | grep 进程名、ps axj | grep 进程名 加上过滤进程信息查看 ps aux | grap test | grap -v grap
task_struct
-
PID ( 标识符 ) :描述本进程的唯一标识符 通过调用getpid()得到PID;
-
状态 : R状态--R状态仅表示该进程允许被放在CPU上运行,不一定被运行,等待运行 CPU将所有的R状态从PCB中拿出来,按照优先级存放在调度队列中 S状态--睡眠状态 : 意味着进程在等待事件完成 ( 比如 Sleep() 函数 )
-
优先级
-
程序计数器( PC指针 寄存器 ) : 存放即将被执行的下一条指令的地址
-
上下文数据 : 将正在执行进程这中的数据保存在PCB中 ( 便于恢复 )
-
进程切换必须要保存 / 恢复 硬件上下文数据
-
时间片 : 是一个进程,占有CPU资源的一个基本单位,当一个进程在一段时间内没有结束,会将该进程强行剥离出来
-
并发 : 在一个时间段内,多个内容同时推进
组织进程--( 所有运行在系统里的进程都已task_struct链表的形式存在内核中 ) ( 刚好的去管理 )
查看进程
-
进程信息可以通过 /proc 系统文件进行查看,如果要查看某个文件的进程信息, ls /proc/(文件名)
-
同样也可以使用top和ps用户技工具获取 ( ps aux | (管道) grep (过滤) test (文件名) | grep -v grep ) top ( 动态查看进程信息 )
系统调用
-
getpid获取当前进程号,getppid获取当前进程父进程进程号
-
进程id ( PID ) 每执行依次就会改变
-
父进程id ( PPID ) 不会改变
-
一个父进程可以有多个子进程 ,一个子进程只有一个父进程
创建进程 -- fork 头文件 #include <sys/type.h>
-
fork有两个返回值 ( 为父进程返回子进程PID , 给子进程返回0 , 若失败子进程返回-1 )
在调用fork之前有一个执行流, fork之后父子进程共享,系统多一个进程,在return之前有两个执行流
fork创建子进程,父进程代码共享,但是数据是私有的, 进程运行时是有独立性的 ( 代码(只读),数据,结构体(PCB) 进程间独立 ) , 所有父子进程创建后,父子进程代码共享, PCB和数据是独立的
-
fork一般情况下要使用if进行分流 ,
-
分流之后父子进程执行各自的代码块
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
int ret=fork();
if(ret<0){
perror("fork");
return 1;
}
else if(ret==0) {
printf("I am child : %d!, ret : %d\n",getpid(),ret);
}
else{
printf("I am father : %d, ret : %d\n",getpid(),ret);
}
sleep(1);
return 0;
}
- 结束进程 1. ctrl c 2. kill -9 PID
进程状态
僵尸进程的危害 :
-
父进程需要知道子进程任务进行的情况如何,方便进行二次决策
-
S状态浅度睡眠D状态深度睡眠
-
S状态和D状态 S状态是一种可以被中断,可以被杀死的状态 D状态是一种不可以被中断的状态
-
Z状态 僵尸状态 : 在该状态下如果不进行回收就会造成内存泄漏 父进程回收子进程获得子进程的PCB,并且释放掉子进程占有的资源
-
( 重要 )进程修改 kill -l //查看系统支持的信号列表 kill -SIGSTOP pid 停止 kill -SIGCONT pid 继续
孤儿进程
-
1号进程也可以看作系统
-
开始都是由bash创建子进程,然后子进程再创建子进程的子进程
进程优先级
-
与权限的区别,权限决定能还是不能,优先级考虑的是先后顺序的问题
信息的含义 ( 重要 )
PRI和NI ( 重要 )
-
优先级存在上下线限,要保证调度器的公平性,要保证CPU雨露均沾
-
优先级都是从80开始的
修改进程优先级的命令
-
nice
-
renice
重要概念
-
IO ( 输入输出 )密集型
-
计算密集型
环境变量
-
main( int argc , char * argv[] , char * env[] )
通过代码如何获取环境变量
-
命令行第三个参数
通过系统调用获取或设置环境变量
-
putenv
-
getenv ( 得到环境变量 )
环境变量通常是具有全局属性的
-
环境变量可以由父进程传给子进程,可以被子进程传递下去 why
程序地址空间 ( 重要 )
为什么子进程能继承父进程的环境变量?
首先考虑进程的虚拟地址空间 ( 用来描述一段空间 ) , 命令行参数和环境变量在栈之上 , 子进程以父进程为模板 ,拷贝PCB、虚拟地址空间 , 所以会被继承下去
内核空间相当于操作系统
每个进程看到得虚拟地址空间有大量准确定义的区(area)构成,每个区都有专门的功能。从最低的地址看起:
-
程序代码和数据:代码是从同一固定地址开始,紧接着的是和C全局变量相对应的数据区。 (应该就是所谓的静态存储空间)
-
堆:代码和数据区后紧随着的是运行时堆。作为调用malloc和free这样的C标准库函数,堆可以在运行时动态的扩展和收缩。(应该就是所谓的动态存储区)
-
共享库:在地址空间的中间附近是一块用来存放像C标准库和数学库这样共享库的代码和数据的区域。(C标准库函数的指令,连接阶段把他们加入到编译后的程序)
-
栈:位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数调用。和堆一样每次我们从函数返回时,栈就会收缩。
-
内核虚拟存储器:内核是操作系统总是驻留在存储器中的部分。地址空间顶部的四分之一部分是为内核预的。
页表是由软件和硬件结合的方式
当进行进程拷贝或者进程替换时就需要一份PCB , 页表 , 虚拟地址空间 , 维护映射关系