计算机-操作系统

计算机出现的初期、是靠人类管理员进行调度的。

排队十分钟、执行三秒钟

后面开发了一个控制程序、在它的指挥下、可以批量执行程序、自动实现切换、不需要人工介入、效率提高了不少。

允许多个程序同时进入计算机执行、如果程序 A 执行输入输出、就把 CPU 空出来给另一个程序 B 执行、一会B 再执行输入输出、再把 CPU 分给 A 执行。彼此交替、就不会浪费。

时间分片

其他程序都在等控制程序翻牌执行、但是左等右等还是不见翻牌。

大伙问控制程序、控制程序说正在执行的程序写了个死循环、死活结束不了。

控制程序也没办法、因为该程序不执行输入输出、控制程序也拿不到 CPU 控制权。

后面搞了一个 “中断” 的技术。就是可以给 CPU 发送中断信号、CPU 收到信号后、就要停下手头工作,转而执行控制程序处理终端信号。这样控制程序就有办法获取控制权了。

为了能够让控制程序获得控制权、人类搞了一个中断源、周期性地给 CPU 发送中断信号、并把这叫作时钟中断

状态

计算机的速度虽然越来越快了、但是执行的程序也越来越多了、程序的功能也越来越复杂。

有些程序处于 sleep 状态或者处于同步等待状态、分配时间片给它们的话只会是浪费。

在这里插入图片描述

优先级

不仅划分了任务状态、还设定了不同的优先级、不同优先级不同队列。优先执行高优先级的程序。

如果有高优先级的程序出现、即使低优先级程序的时间片还没用完、也会被剥夺执行机会。这叫抢占

程序运行的实体:进程

每个进程都有一个身份证号码、叫作 PID

PID 后面还有一个数字、就是它的父进程。

进程调度

操作系统给每个进程都分配了时间片、让进程轮流来执行、因为这段时间很短、一般都在毫秒级别的、所以人类很难发现。

你可能会问、CPU正在执行进程、操作系统是怎么把进程们赶出去、让出 CPU的?

这要归功于 CPU 提供了一个叫中断的技术、只要给它发送一个中断信号、CPU就会暂停手里的活、转而执行处理中断的程序。

计算机主板上的那些外部设备、比如键盘、鼠标、网卡等就是通过这种方式来和 CPU 联系的。

CPU 有很多不同的中断信号、除了这些外部设备发送的中断信号、还有一个时钟中断、会周期性地发送给 CPU。而所有的中断处理程序都是操作系统在启动的时候就安排好的。所以一旦有中断信号来、操作系统就会抢到执行的机会。

进程和线程

以前的时候、每个进程只有一个执行流、想要提高病发量、就需要创建多个进程。但是进程之间是被隔离的、彼此联系不是很方便。虽然操作系统为我们提供了进程间的通信方法。但是还是很麻烦。而且还需要为每个进程提供完整的地址空间、实在浪费资源。于是在想、一个进程里能不能有多个执行流、线程就诞生了。

一个进程里面有多个执行流也就是多个线程、每个线程都有最多执行上下文和堆栈、无不影响、而去线程看到的地址空间是同一个、他们之间的通信就很方便。

所以现在操作系统的调度单位就从原来的进程变成线程了

CPU的执行流:线程

每个线程都有一个 task_struct 结构、里面详细记录了每个线程的信息、其中就包括了线程ID和一些执行时间

task_struct{
	pid
	tgid //线程组id、实际上是进程Id
	.......
	utime,stime
	prev_utime,prev_stime
}

线程的本质就是一个个执行流、指定了 CPU 从进程空间的哪个位置开始执行指令。

以前一个 task_struct 代表着一个进程、而现在代表着一个线程、同一个进程中的所有线程组成了线程组、所以它们拥有一样的 tgid ---- 线程组id

系统调用

程序的地址空间分为两大部分、一部分是用户地址空间、是应用程序能访问的内存空间、另一部分是内核地址空间、是操作系统内核所在的内存区域。

系统调用表

操作系统把管理文件、内存、进程、线程、网络还有硬件设备等资源的操作都封装成一个个函数、并专门提供了几百个函数出来、供你们这些应用程序使用。这些个函数就是系统调用。

sys_open 函数就是其中一个、通过它就能打开文件。

这些系统调用函数都位于内核地址空间、为了安全考虑、这些应用程序是没法直接访问内核地址空间的内存的、所以要单独设计一条通道、就像虫洞、连接用户态地址空间和内核态地址空间。应用程序想要使用这些系统调用、就从这个虫洞过来、然后查系统调用表获取函数地址然后去调用。

每个函数的地址都是机密、而且为了安全、这些地址会随着系统每次启动而变化、不是一个固定的地址。

每个应用程序的线程都有两个栈、一个在用户态地址空间、一个在内核态地址空间、专门为了在内核态调用时使用。

CPU 中断和异常

中断描述符表-IDT

中断就是有重要的事情发生、打断你们先吃手头工作、让出 CPU 必须去处理。

比如键盘按下、网络中的数据包到来等

异常就是 CPU 在执行线程的代码指令时出现错误。

比如除法时除数为 0、访问内存地址错误等。

CPU一旦发现有问题、就会强制改变执行流、来这里处理这些异常。

中断和异常差不多?

确实差不多、它们都是用 IDT 来一起记录、不过实际上差别还是很大的、最大的区别在于中断是异步的、异常是同步的。

中断什么时候来你是不知道的、你是被迫打断的、而异常是你们执行指令主动造成的。

IDT 是做啥用的?

打断之后去哪里?IDT 就是把所有中断和异常发生后要去处理的地方记录成一个表。总共有 256 条记录。

这些处理函数是操作系统启动的时候设定好的

信号

信号 Signal 用来告诉进程有事情发生了

比如 Ctrl+C 进程就是发送 SIGINT 信号、kill 进程就是 SIGTERM 信号、数学运算错误就是 SIGFPE。

总而言之、就是一个通知

信号的处理

进程在运行的过程中、回因为系统调用、中断、异常等种种原因从用户态地址空间进入内核态地址空间运行、当它们返回点时候、就回去检查有没有信号需要处理、如果有的话就会去执行对应的处理函数。

要是系统一直没有系统调用、中断和异常发生。信号岂不是一直得不到处理?系统调用和异常不好说、但是中断是一只发生着点、操作系统依靠时钟中断来调度所有进程、所以基本上等不了太久、信号就有机会被处理。

为了安全起见、信号自定义处理函数只能在用户态模式下运行。

权限管理

UGO(user,group,other) Linux 操作系统为所有文件针对所属用户、所属的用户组和其他用户分别设置了访问权限。读 Read 写 Write 可执行 Execute 三种权限组合、总共用 9 个比特位来表示、1 表示有权限、0 表示没有权限。为了方便表示、每三位用一个整数表示。

ACL

Access Control List 访问控制列表。

UGO 的权限管理方式有些粗暴、很多细粒度的权限它做不了、为了更加精细化的管理、Linux 推出了新的权限控制策略。在 UGO 的基础上、可以单独记录一些细粒度的权限信息。比如单独制定某个用户或用户组允许其对文件的访问、这些信息就构成了一个访问控制列表、把这个表的地址放到 inode 里。

docker 容器

隐藏文件系统 chroot 与 pivot_root

作为一个容器、首要任务就是限制容器中进程的活动范围–能访问的文件系统目录。

通过这两个函数、可以伪造一个文件系统来欺骗容器中的进程。

为了不露出破绽、Docker 把操作系统镜像文件和进程依赖的目录和文件通过联合挂载的方式、挂载到容器进程的根目录下、变成容器的 rootfs、和真实系统目录一摸一样。

https://developer.aliyun.com/article/841679

https://zhuanlan.zhihu.com/p/623204986

进程隔离:命名空间

如何把真实系统所在的世界隐藏起来、别让容器中的进程看到、比如宿主机上面的进程列表、网络设备等。

命名空间 namespace

Linux 系统提供的一个机制、通过它可以划定一个个命名空间、然后把进程划分到这些命名空间中。每个命名空间都是独立存在的、命名空间中的进程无法看到空间之外的进程、用户、网络等信息

行为等限制 CGroup

CGroup 和 namespace 类似、也是 Linux 的一套机制、通过它可以划定一个个分组、然后限制每个分组使用都资源、比如内存都上限制、CPU的使用率、磁盘空间总量等。系统内核回自动检测和限制这些分组都进程资源使用量。

https://book.douban.com/subject/36428782/

  • 32
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值