操作系统
操作系统的面试题目
操作系统
1.进程线程
1.0 什么是进程
进程是资源分配的基本单位。
进程是程序在处理器的一次执行过程
进程是可以和别的进程并行执行的计算
是在一个数据集合的运行过程,是系统进行资源分配和调度的一个独立单位
进程的组成
进程控制块PCB:
每个进程一个PCB,用来标识进程的存在,又能刻画瞬间特征的数据机构
程序段
:能被进程调度到CPU 执行的代码段
数据段:
保存原始数据或中间数据。
进程标识符:
就好比人类的身份证,用来区分。
进程的当前状态:
作为分配资源的依据
程序和数据地址:
指出进程的程序和数据所在的地址
进程优先级:
反映进程执行优先级。
通信信息
:记录和其他进程的通信情况
1.1 为什么说PCB(进程控制块)是进程存在的唯一标识?
PCB是操作系统为每个进程分配的一个数据结构,其作用是使程序可以独立执行。
PCB中存着进程执行的程序和数据内存地址,进行内存访问,通信时也需要访问PCB,进程暂停执行时,也会将状态保存在PCB中,系统总是通过PCB对进程进行控制。说白了,PCB就好像进程的管家。
1.2 进程的状态与转换
1.3 进程和线程比较
一个进程可以创建很多子进程。
进程和线程的比较
这一块是常考题目
我们主要从调度,拥有资源 ,并发性,系统开销等
方面对其进行比较
调度:
在传统的操作系统中,拥有资源和独立调度的单位都是进程,引入线程之后,调度的最小单位就变成了线程,但是拥有资源的最小单位还是进程,另外在同一个进程中,线程的切换不会影响进程,但是不同的进程中的切换则会引起进程切换。
拥有资源:
不论是传统的操作系统,还是设有线程的操作系统,进程都是资源分配的最小单位。
并发性:
在引入线程的操作系统中,不仅进程之间可以并发,线程之间也可以并发,这使得操作系统具有更好的并发性。
系统开销
:创建进程或撤销进程的同时,系统都要为之分配或回收资源,在进行进程切换时,涉及当前进程CPU 环境的保存和新环境的设置,线程切换时,只需保存和设置少量寄存器内容,因此开销很小
。总的来说就是线程间切换的开销更小,同步和通信很容易实现。
推荐阅读:线程和进程的区别是什么?
1.4 线程模型
多对一模型:多个用户级线程映射到一个内核级线程上
一对一模型:一个用户级线程映射到一个内核级线程上,堵塞时不会影响其他线程的运行。
多对多模型:不仅可以使多个用户级线程真正意义上并行执行,而且不会限制用户线程的数量。
1.5 进程切换
进程切换的速度是远小于线程切换的,举个不太恰当的例子,我们如果把进程比作房子,线程比作卧室的话,线程切换则是在每个卧室之间,来回穿梭,不用更换衣物,鞋子,但是我们如果要去邻居家(另一个进程)那么则需要更换衣服鞋子,这就是线程切换和进程切换。
上下文切换,保存当前情况,将运行情况存到PCB中等
进程切换为什么慢?
这就需要说到虚拟地址的地方了,因为每个进程都有自己的虚拟地址空间
,然后线程是共有进程的虚拟空间,所以进程切换的话需要虚拟地址空间的切换。这个过程是比较慢的。
另外进程通过查找页表,将虚拟空间映射到物理地址空间。这个过程是比较慢的,所以通常使用Cache来保存那些经常被查找的地址映射,然后进程切换的话,也会导致页表的切换,进而导致Cache失效,命中率降低,进而就会导致程序运行变慢。
推荐阅读:送命题:进程切换与线程切换的区别
1.6 协程
协程又叫微线程,
在有大量IO操作业务的情况下,我们采用协程替换线程,可以到达很好的效果,一是降低了系统内存,二是减少了系统切换开销,因此系统的性能也会提升。
协程多用于异步I/O这样性能最好,堵塞I/O不能完全发挥出优势。
我们可以把协程理解成用户态的线程,操作系统不知道协程的存在,所以协程切换时不需要由操作系统控制,可以由自己控制,这样就节省了操作系统资源。
另外一个线程可以由多个协程,是线程内调度的基本单位,然后有自己的寄存器。
1.7 上下文切换的过程
- 挂起一个进程,将这个进程在CPU中的状态(上下文信息)存储于内存的PCB中。
- 在PCB中检索下一个进程的上下文并将其在CPU的寄存器中恢复。
- 跳转到程序计数器所指向的位置(即跳转到进程被中断时的代码行)并恢复该进程
推荐阅读:深入理解CPU上下文切换
进程通信和线程通信
1.8 进程通信
进程通信就是指进程间的信息交换
- 管道
- 消息队列
- 共享内存
- 信号量
- 信号
- Socket
管道
ps auxf | grep mysql
中间的 | 就是管道,匿名管道但是只能单向传输。然后只能在父子进程之间进行传输。
命名管道,可以在无关系的进程之间进行传输。
管道通信,效率较低。
消息队列
消息队列 的通信模式就可以解决。比如,A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程需要的时候再去读取数据就可以了。同理,B 进程要给 A 进程发送消息也是如此。消息队列是保存在内核中的消息链表
缺点通信不及时,并且有大小限制
共享内存
这个比较有意思,就是拷贝来拷贝去,进行拷贝,有点类似留言板的功能
并发情况下会出问题
信号量
PV操作,用于多进程的情况,P操作为减 1 ,看看资源是否已经被调用,信号量就是为了解决并发情况下的安全性,和加锁原理类似。
信号
异常状态下的进程间通信,可以使用 kill -l 查看,给进行发信号,让其执行某些命令,比如 kill - 9 pid 就是
socket
不同主机间的进程通信
推荐阅读:张三同学没答好「进程间通信」,被面试官挂了....
写的非常牛批
1.9 线程通信
wait notify
加锁
volatile等
共享内存
进程调度
1.10 进程调度的准则
CPU利用率
:如何调度可以使CPU的利用率达到最大
系统吞吐率:
系统吞吐量表示单位时间内CPU完成作业的数量
响应时间:
调度策略要尽量保证响应时间在用户接受的范围内
周转时间
:周转时间是作业从开始到完成的所需的时间,尽量使这个时间较小。
1.11 进程调度算法
进程调度含义:当某一个进程正在处理器上执行时,这时来了一个新的更紧急的进程,我们此时应该如何调度。
调度分为抢占式方式
和非抢占式方式。
抢占式:很容易理解,当一个进程正在执行时,又来了一个优先级较高的进程进入就绪队列,则立即停止当前进程,然后将处理器分配给优先级更高的进程。
非抢占式:来了优先级更高的进程时,我继续执行,等我执行完了之后,新进程再继续执行。
常见的进程调度算法
1.先来先服务:
根据进入就绪队列的顺序来执行,该方法分为非抢占式,比较公平。用的不太多了
2.短作业优先调度:
这个方式就是把CPU分配给能够最快完成工作的进程。
3.优先级调度:
这个是常用的进程调度算法,基本思想就是将CPU分配给优先级最高的进程。这个优先级是在进程创建时确定的,确定之后在运行期间不再改变。
4.时间片轮转调度算法:
将所有就绪进程排成一个队列,进程调度程序总是选择第一个进程执行,每个进程执行的时间相同,所以时间片的大小设定就比较重要。
5.高响应比
:综合了先来先服务和短作业优先两种调度算法的特点。考虑了等待时间和执行时间两个因素。
选择响应比高的进行执行
6.多级队列调度算法
将就绪的进程分到多个队列中去,每个进程属于一个队列,每个队列采用一种调度算法。
7.多级反馈队列调度算法
:多级反馈调度是时间片轮转和优先级调度算法
的综合与发展,多个队列中的优先级不同,时间片轮转的大小也不一样。通常是优先级越高,执行的时间片越短,刚开始按照先来先服务准则,心来的一个新进程是放在最后一个队列的末尾,如果在该时间片内不能执行完毕,则将其移到上一个优先级的队列末尾,继续排队。
1.12 同步与互斥
推荐阅读:图解系统:互斥与同步
1.13 进程同步
直接相互制约,某一进程若是收不到另一进程给他提供的必要信息就不能继续执行下去。
1.14 进程互斥
间接相互制约,某个进程要使用某个资源,但是这个资源被另一个进程使用,所以该进程只能等另一个进程使用完毕,才能继续使用。
消费者和消费者之间就是互斥关系,消费者和生产者之间就是同步关系
。
1.15 临界资源和临界区
同时只能允许一个进程访问的资源,统称为临界资源。
临界区是临界资源的一部分,临界资源可以分为进入区,临界区,退出区,剩余区
进入区:
好比加锁区,告诉别人里面已经有人了,不要进来了。
临界区:
进程中用于访问临界资源的代码
退出区:
清除正在临界区内的标志,解锁区。
1.16 如何防止两个进程进入临界区
很容易理解,我们可以用白话文来回答
闲时让进:空闲状态你可以进入
忙则等待:有人正在用,你等一等
有限等待:不会让你一致等的放心好啦。
让权等待:你出问题了,就别占着位置啦,让别人用吧。
1.17 同步和互斥实现和经典例子
互斥:加锁,信号量
同步:信号量
经典同步问题:消费者-生产者问题
一组生产者像一组消费者提供产品,他们共享一个缓冲区,生产者会向里面投放物品,消费者从里面取走产品。
但是这个里面存在一个问题,那就是缓冲区内没有物品,消费者不断取的过程,和已经满了生产者不断放入的情况,还有就是多个消费者取的情况。这时我们可以设置三个信号量,一个是是满,一个是空,一个是单一访问(多消费者,多生产者情况)。
读者写者问题
一块黑板,老师们只往上面写,学生只能读。
读者写者问题有点像我们的读锁和写锁。
可以多个读者同时读,但是只能有一个写者同时写。
如果写者正在写,此时不允许其他人读和写。
当读者正在读的时候,写者不能写
解决方法:读者和写者互斥,可以多个读者同时进入,只能由一个写者进入,写者进入时,读者不能进入。
哲学家进餐问题
5 个哲学家围坐在一起,桌上放着 5 个筷子,每两个哲学家之间放一根,我们此时思考一下,如果五个人同时只拿起自己左边或右边的筷子,那么这样他们每个人只有一个筷子,这样就会造成都没有机会进餐。也就是死锁的情况。
我们如何保证哲学家吃饭的工作有序进行,而不会出现没有饭吃的情况。
第一种解决方法:可以加个信号量,每次只允许一个人就餐,当某个人就餐时,其他人要等他就餐完毕才能获得筷子。
这种方法是低效的,因为只能有一个人进餐,但是我们一共有五个筷子,理论上可以两个人可以同时就餐。
那我们可以这样解决
给哲学家编号,让奇数号先取左边,再取右边,偶数号先取右边,再取左边。我们发现 1,2哲学家竞争 1 号筷子,3,4哲学家竞争 3 号筷子,1,5哲学家竞争 5 号筷子,竞争的都是奇数位筷子,最后肯定有两个人可以获得进餐机会,然后让没能进餐的进入队列即可。
1.18 管程
用来管理进程的工具,防止进程访问共享资源时,产生死锁的情况。
2.死锁
2.0 死锁产生的条件
死锁产生的原因是竞争资源
请求和保持:
请求新资源,保持住占有资源
互斥:
某一时刻下,一个资源只能一个进程所占有
不可剥夺:
获得的资源没有使用完时,别人不可以抢走
循环等待
:没有获得新资源,绝不死心。
2.1 处理死锁的方法
鸵鸟法:
顾名思义,对死锁不管不问
预防死锁
:设置某些限制条件,破坏死锁产生的四个条件之一
避免死锁
:资源分配的动态过程中,用某种方法防止系统进入不安全状态,从而避免死锁的发生。
检测死锁:
专门喊个人来检测死锁是否存在。
2.2 死锁预防
破坏四个条件之一
互斥条件:不太可能通过这个来解决
请求和保持:静态分配,进程运行之前先分配所有资源给他
不可剥夺:也可以通过这个来解决,当某个资源长时间不能获得需要的新资源时,则放弃他的所有资源
循环等待:我认为从循环等待下手比较好,当等待一段时间还没有获得资源时,则放弃等待。
2.3 死锁避免
安全状态
给进程分配资源之前,先判断是否给其分配后,会导致系统进入不安全状态,如果不会则进行分配。
另外需要注意的是,不是进入不安全状态就一定会产生死锁,而是可能产生死锁。
银行家算法
需要定义很多数据结构
最大需求矩阵:最大需求
可用资源向量:可用资源
分配矩阵:分配了多少
需求矩阵:还需要多少
具体执行如下
申请资源Ri代表每个进程申请的资源数目。那么需要注意三个地方
申请资源数目,不能小于需要的资源数目,也不能大于含有的资源数目,然后再进行预分配,分配过之后进行安全检查,判断是否有可能使其进入不安全状态。
监督人
2.4 死锁的检测和解除
死锁检测
资源分配图
我们可以通过资源分配图来检测进程的资源占用情况及申请情况,进而来判断是否产生了死锁。
死锁解除
可以通过,剥夺资源,进程回退,进程撤销来解除死锁。
2.5 死锁和饿死
进程调度不公平的时候,容易发生进程饿死的情况
3.内存管理篇
基础概述
3.0 内存管理的功能?
内存的分配和回收
地址变换
:程序的逻辑地址和内存中的物理地址不一致,提供地址变换功能,将逻辑地址变为物理地址
扩充内存
:借助虚拟存储技术,为用户提供比内存大的内存空间
存储保护
:各个进程之间互不干扰。
3.1 虚拟地址和物理地址
虚拟地址:MMU经过转换之后制造出来的内存空间
物理地址:是虚拟地址变换后的最终地址,实打实存在的,可以根据物理地址从主存中获取
我们通过一个小例子来加深理解
打个比方,你有一本笔记本,每页都有页码,现在是空的,你可以在上边记东西。你要上语文数学英语三门课,三门课的笔记要记在基本上。显然,这三门课是混着上的,所以如果你从前往后记笔记,这三门课的内容是混起来的。
你需要不时翻找每门课的笔记,但是因为内容都是混在一起的,查找很困难,所以你想到了一个办法:记笔记的时候,记语文的页只记语文,不把其他课的内容混在一起。并且用单独的三页记录每门课的笔记的页码。你管这种记录方式叫做页表。笔记每多记一页,就在相应的学科的页表上记上笔记本页数。
于是你需要找语文第10页的时候,只要看语文的页表,发现语文第10页放在笔记本的第20页上,那么你只要翻到笔记本第20页就能看到你想要的内容了。
在这个例子中:
笔记本 -- 物理内存
笔记本页码 -- 物理地址
笔记页 -- 页框 (Page frame)
页表 -- 页表 (Page table)
页表内容 -- 页表项 (Page table entry)
语文页码 -- 虚拟地址
推荐阅读:能不能简单的讲解一下逻辑地址和物理地址 逻辑寻址和物理寻址 的区别?
3.2 覆盖和交换?
覆盖技术
,就是把一个大程序划分为一系列覆盖,每个覆盖是相对独立的程序单位。把不要求同时装入内存的覆盖组成一组,称为覆盖段。
覆盖打破了必须将一个进程的全部信息装入内存后才能运行的限制,但当同时运行程序的代码量大于主存时仍不能运行。
交换技术
,交换技术就是把暂时不用的某个程序及数据部分
,从内存移到外存中,以便腾出必要的内存空间。但是运行程序的大小,仍然受内存大小限制。
3.3 内存分配方式
连续分配
单一连续分配
古老的操作系统,只分配一个作业到内存中,用不了的则浪费了。
这样会产生内部碎片,内部碎片的含义也很容易理解,用不了的地方,浪费了,外部碎片,还剩一点但是不足以再进行分配。
固定分区分配
比单一分配进步一点,但是给内存分块,然后进行分配,块的大小可以是固定的,也可以是不固定的。这样就可以在内存中分配多个作业,但是同样会产生内存碎片。
动态分区分配
不事先建好分区,在内存分配的过程中动态建立分区。通过空闲分区表来进行分配。
主要由有四种方法
首次适应:根据地址从小到达进行搜索,直到搜索到合适的位置。
最佳适应:将空闲分区容量,按从小到大的方式进行排序,找到合适的则进行分配
最坏适应:将空闲分区容量,按照从大到小的方式进行排序,找到合适的则进行分配。
邻近适应:是一个循环队列,不每次都从头部开始寻找,而是循环查找,直到查找到合适的地方。
非连续分配方式
非连续分配方式也很容易理解,将内存分为很多块,并创建一个页表进行保存页号和块号,类似于哈希表,可以直接通过页表,查找到程序页在内存的哪个块中。
但是这样有一个弊端,那就是需要多次访问内存,会让访问速度降低,所以我们引入快表机制,快表又叫联想寄存器,容量很小,用于保存经常访问的块号和页号。这因为有快表,所以页表总被称之为慢表。
3.4 虚拟内存
之前说到的内存分配方法,存在这两种情况,一次性(完全存入内存才可执行),驻留性(作业长驻内存直到运行结束)一个程序中,有的代码执行很少,程序所访问的空间也很局限。
虚拟内存管理技术就是能够让作业部分装入就可以运行
的存储管理技术
3.5 虚拟内存实现方式
程序装入时,将程序的一部分放入内存,而将其余部分放在外存,这时启动程序,边执行边把所需的部分调入内存。另一方面,操作系统将内存中暂时不用的放到外存中,从而腾出空间。这样看,操作系统为用户提供了一个存储容量比实际内存大的多的存储器。
虚拟内存的特征
离散性:内存中离散存储(不是专有)
多次性:多次放入
交换性:可以和暂时不用的页进行交换
虚拟性:让人觉得比实际大得多
顺便在这里提一嘴缺页中断,当内存中没有需要的页时,则会产生一个缺页中断,然后去外存中找到,并交换到内存中。
推荐阅读:如何理解虚拟内存
3.6 页面置换算法
最佳页面置换
:每次淘汰以后不再使用的或以后最迟使用的页面
先进先出
最近最少使用
时钟置换算法
当发生缺页中断时,算法首先检查表针指向的页面:
如果它的访问位位是 0 就淘汰该页面,并把新的页面插入这个位置,然后把表针前移一个位置;
如果访问位是 1 就清除访问位,并把表针前移一个位置,重复这个过程直到找到了一个访问位为 0 的页面为止;
最不常用算法
页面缓冲算法
3.7 管理方式
在操作系统中,进程是以页为单位加载到内存中的,按需分页是一种虚拟内存
的管理方式。在使用请求分页的系统中,只有在尝试访问页面所在的磁盘并且该页面尚未在内存中时,也就发生了缺页异常
,操作系统才会将磁盘页面复制到内存中。
3.8 抖动和缺页率
抖动
:若选用的置换算法不合适,可能会出现这种现象,刚被淘汰的页面,过后不久又要访问,调入不久又调出,如此反复,使得大部分时间用在页面的调入调出上,几乎不能完成有效的工作。
缺页率
:也就是进行页面交换的次序。
belady异常:随着分配物理块数的增加而增加,这种奇怪的现象就是belady异常。
4.文件管理篇
如何实现目录
线性表
散列表
4.0 文件的实现
文件的实现主要是指文件在存储器上的实现
外存分配方式
(1)连续分配
这是最简单的分配方式,分配之前需要直到文件的大小,然后给予分配即可。
(2)链接分配
- 隐式链接
- 显式链表
和隐式分配差别不大,只不过是将查询过程放到了文件分配表中,速度更快一些。
- 索引分配
给每个文件分配一个索引块,通过索引块进行查找
如果索引表的大小超过了一个物理块,则再创建一个索引作为二级索引即可。
4.1 磁盘结构中的信息
引导控制块
分区控制块
目录结构
文件控制块
4.2 磁盘调度算法
先来先服务
最短寻道时间
:磁盘接收到读命令之后,磁头从当前位置移动到目标位置,所需时间为寻道时间,这个算法就是选择与当前磁头所在轨道距离最近的请求作为下一次服务对象。
扫描算法
:在磁头的当前移动方向上,找到离磁头最近的磁道
循环扫描
:规定磁头的单向移动,进行循环扫描
5.设备管理
设备控制器:位于CPU 和I/O之间,其接收来自CPU的指令,并控制I/O设备。
5.1 几种I/O控制方式
1.程序直接控制方式
向CPU和I/O设备设备控制器发出命令之后,然后就需要一直检测状态寄存器的值,判断是否结束任务,结束之后再去执行下一个任务。
2.中断控制方式
这个也很容易理解,当CPU 向设备控制器发出启动指令后,则去做其他工作,设备控制器完成任务后,则会发送一个中断指令,告诉他,我已经完成任务了,然后让其继续回来处理任务。但是这样也存在问题,中断过多的话,则会耗费大量CPU时间。
3.DMA控制方式
数据传输的基本单位是块,然后传输过程是DMA控制器直接于内存交换,仅在传送一个或多个块的开始或结束时,才需CPU干预。
中断控制方式在每个数据传输完之后中断CPU,DMA是一批数据全部传输完才进行中断。
4.通道控制方式
通道控制方式和DMA类似,但是所需要的CPU干预更少,我们可以将他理解成一个简单的控制器,代理CPU进行处理。
5.2 I/O软件的层次结构
5.3 I/O子系统
I/O核心子系统是设备控制的各类方法,其提供的主要服务就是I/O调度,高速缓存与缓冲区、设备分配与回收、假脱机。
I/O调度:
就是确定一个好的顺序来执行I/O请求。因为应用程序所发布系统调用顺序不一定总是最佳选择,所以需要通过调度来改善系统的整体性能。主要是通过重新安排任务队列顺序以改善系统总体调用。
引入缓存
:引入缓冲后可以降低设备对CPU的中断频率,放宽对中断响应时间的限制。
缓存的分类
单缓存
双缓存,可以交替使用,提高并行速度
循环缓存:顾名思义
缓冲区
5.4 假脱机技术
这个是经常用到的,我们系统中有一些独占设备,然后某个进程获得了独占设备的使用权,但是却不经常使用,却又卡着让别人用不了,这就造成了资源的浪费,所以我们将独占设备改造成共享设备,提高利用率。
主要原理是,利用输入缓冲区,输入井,输出缓冲区,输出井来完成。
6.其他补充
6.1 什么是用户态和内核态
核心态:又指管态、系统态,是操作系统管理程序执行时
机器所处的状态。具有较高特权,能执行一切指令。
用户态:是用户程序执行时机器所处的状态,特权较低,只能执行规定内的指令,访问指定的部分。
总结:核心态特权高,可以横行霸道,拥有一切特权,执行指令,访问内存。用户态特权小,只能执行部分指令,访问部分内存。
另外用户不能直接调用核心态程序,只能通过中断,由中断系统将其转入操作系统内的相应程序。
特权指令:只能有操作系统内核部分使用,不允许用户直接使用的指令,I/0指令。设置中断屏蔽指令、清内存指令,存储保护指令,设置时钟指令。
推荐阅读:从根上理解用户态与内核态
6.2 中断和异常
中断:又称为外中断,是系统正常功能的一部分,使系统停止当前运行的进程而执行其他进程。然后操作系统处理完该任务之后,再来处理中断前的命令。
异常:是由错误引起的,如文件损坏、进程越界等。
6.3 Linux 的同步机制
同步就好比:「操作 A 应在操作 B 之前执行」,「操作 C 必须在操作 A 和操作 B 都完成之后才能执行」等;
互斥就好比:「操作 A 和操作 B 不能在同一时刻执行」;
可以使用互斥锁
6.4 虚拟技术你了解吗?
就是把物理实体转化为逻辑实体
主要有两种虚拟技术:时分复用技术和空分复用技术
6.5 什么是I/O多路复用?
通过线程池来处理已连接的 socket
这是一个全局队列,然后调用之前需要加锁。
I/O多路复用
一个进程虽然任一时刻只能处理一个请求,但是处理每个请求的事件时,耗时控制在 1 毫秒以内,这样 1 秒内就可以处理上千个请求,把时间拉长来看,多个请求复用了一个进程,这就是多路复用,这种思想很类似一个 CPU 并发多个进程,所以也叫做时分多路复用 。
select / poll / epoll
边缘触发:提醒一次
水平触发:没有做,就一直提醒。
6.6 大端小端
这里我们先说一下用8位16进制,描述32位二进制数,这里有两种说法为什么可以表示
一种是16等于 2 的 4 次方,刚好可以表示
另一种是 0000-1111刚好为16。
所以我们经常用 8 位 16 进制来表述 32 位 2 进制数。
然后一个字节是 8 位,那么两位 16 进制数则为 一个字节。
大端模式:高位字节放在内存的低地址端,低字节位放在内存的高地址端
小端模式:高位字节放在内存的高地址端,低字节位放在内存的低地址端。
另外我们应该如何检测是大端模式还是小端模式呢?
使用C语言的 union 共同体
#include <stdio.h>
int main()
{
union{
int a; //4 bytes
char b; //1 byte
} data;
data.a = 1; //占4 bytes,十六进制可表示为 0x 00 00 00 01
//b因为是char型只占1Byte,a因为是int型占4Byte
//所以,在联合体data所占内存中,b所占内存等于a所占内存的低地址部分
if(1 == data.b){ //走该case说明a的低字节,被取给到了b,即a的低字节存在了联合体所占内存的(起始)低地址,符合小端模式特征
printf("Little_Endian\n");
} else {
printf("Big_Endian\n");
}
return 0;
}
如果 b = 1 那么则为小端存储,低字节位存在低地址位。
6.7 什么是零拷贝?
推荐阅读:原来 8 张图,就可以搞懂「零拷贝」了
6.8 BIO(同步阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)
BIO堵塞IO:发现被使用,则一直等待
NIO:发现被使用,先去干别的,然后每隔一段时间再回来,然后看看用完没。
AIO:发现被使用,先去干别的,等结束了我通知你,你再回来