操作系统

线程/进程

阻塞,非阻塞,同步,异步的区别?

同步:

指的是协同步调。既然叫协同,所以至少要有2个以上的事物存在。协同的结果就是:

多个事物不能同时进行,必须一个一个的来,上一个事物结束后,下一个事物才开始。

异步:

步调各异。既然是各异,那就是都不相同。所以结果就是:

多个事物可以你进行你的、我进行我的,谁都不用管谁,所有的事物都在同时进行中。

阻塞:

阻碍堵塞。它的本意可以理解为由于遇到了障碍而造成的动弹不得。

非阻塞:

由于没有遇到障碍而继续畅通无阻。

同步阻塞,相当于一个线程在等待。

同步非阻塞,相当于一个线程在正常运行。

异步阻塞,相当于多个线程都在等待。

异步非阻塞,相当于多个线程都在正常运行。

参考:

【面试】迄今为止把同步/异步/阻塞/非阻塞/BIO/NIO/AIO讲的这么清楚的好文章(快快珍藏)

什么是阻塞,非阻塞,同步,异步? - 知乎

对操作系统异步I/O操作的理解?

首先先了解阻塞,非阻塞,同步,异步的区别

从计算机内核 I/O 而言,异步 / 同步和阻塞 / 非阻塞实际上时两回事。

I/O 的阻塞与非阻塞

阻塞模式的 I/O 会造成应用程序等待,直到 I/O 完成。同时操作系统也支持将 I/O 操作设置为非阻塞模式,这时应用程序的调用将可能在没有拿到真正数据时就立即返回了,为此应用程序需要多次调用才能确认 I/O 操作完全完成。

I/O 的同步与异步

I/O 的同步与异步出现在应用程序中。如果做阻塞 I/O 调用,应用程序等待调用的完成的过程就是一种同步状况。相反,I/O 为非阻塞模式时,应用程序则是异步的。

异步I/O需要通过轮询拿到结果。

当进行非阻塞 I/O 调用时,要读到完整的数据,应用程序需要进行多次轮询,才能确保读取数据完成,以进行下一步的操作。

轮询技术的缺点在于应用程序要主动调用,会造成占用较多 CPU 时间片,性能较为低下。现存的轮询技术有以下这些:

  • read
  • select
  • poll
  • epoll
  • pselect
  • kqueue

read 是性能最低的一种,它通过重复调用来检查 I/O 的状态来完成完整数据读取。select 是一种改进方案,通过对文件描述符上的事件状态来进行判断。操作系统还提供了 poll、epoll 等多路复用技术来提高性能。

轮询技术满足了异步 I/O 确保获取完整数据的保证。但是对于应用程序而言,它仍然只能算时一种同步,因为应用程序仍然需要主动去判断 I/O 的状态,依旧花费了很多 CPU 时间来等待。

上一种方法重复调用 read 进行轮询直到最终成功,用户程序会占用较多 CPU,性能较为低下。而实际上操作系统提供了 select 方法来代替这种重复 read 轮询进行状态判断。select 内部通过检查文件描述符上的事件状态来进行判断数据是否完全读取。但是对于应用程序而言它仍然只能算是一种同步,因为应用程序仍然需要主动去判断 I/O 的状态,依旧花费了很多 CPU 时间等待,select 也是一种轮询。

理想的异步 I/O 应该是应用程序发起异步调用,而不需要进行轮询,进而处理下一个任务,只需在 I/O 完成后通过信号或是回调将数据传递给应用程序即可。Linux 平台下没有完美的异步 I/O 支持。

参考:

深入浅出Node.js(五):初探Node.js的异步I/O实现

Linux中有哪些IO模型?

在Linux(UNIX)操作系统中,共有五种IO模型,分别是:阻塞IO模型、非阻塞IO模型、IO复用模型、信号驱动IO模型以及异步IO模型

其中前四种都是同步的。

阻塞IO模型

阻塞 I/O 是最简单的 I/O 模型,一般表现为进程或线程等待某个条件,如果条件不满足,则一直等下去。条件满足,则进行下一步操作。

非阻塞IO模型

应用进程与内核交互,目的未达到之前,不再一味的等着,而是直接返回。然后通过轮询的方式,不停的去问内核数据准备有没有准备好。如果某一次轮询发现数据已经准备好了,那就把数据拷贝到用户空间中。

信号驱动IO模型

应用进程在读取文件时通知内核,如果某个 socket 的某个事件发生时,请向我发一个信号。在收到信号后,信号对应的处理函数会进行后续处理。应用进程预先向内核注册一个信号处理函数,然后用户进程返回,并且不阻塞,当内核数据准备就绪时会发送一个信号给进程,用户进程便在信号处理函数中开始把数据拷贝的用户空间中。

IO复用模型

多个进程的IO可以注册到同一个管道上,这个管道会统一和内核进行交互。当管道中的某一个请求需要的数据准备好之后,进程再把对应的数据拷贝到用户空间中。这里的IO复用模型,并没有向内核注册信号处理函数,所以,他并不是非阻塞的。

异步IO模型

应用进程把IO请求传给内核后,完全由内核去操作文件拷贝。内核完成相关操作后,会发信号告诉应用进程本次IO已经完成。

五种IO对比:

参考:

漫话:如何给女朋友解释什么是Linux的五种IO模型? - 掘金

进程间通信方式

1.管道通信

2.消息队列通信

3.信号量通信

4.信号通信

5.共享内存通信

6.套接字通信

参考:

进程间8种通信方式详解_在努力!-CSDN博客_进程间通信方式

什么是协程,和线程什么关系?

协程是一种比线程更加轻量级的存在。你可以把协程看做跑在线程上的任务,一个线程上存在多个协程,但是在线程上同时只能执行一个协程。

比 如当前执行的是A协程,要启动B协程,那么A协程就需要将主线程的控 制权交给B协程,这就体现在A协程 暂停执行,B协程恢复执行;同样,也可以从B协程中启动A协 程。通常,如何从A协程切换到B协程,我们就把A协程称为B协程的父协程 。

正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。最重要的是,协程不是被操 作系统内 核所管理,而完全是由程序所控制(也就是在用戶态执行)。这样带来的好处就是性能得 到了很大的提升, 不会像线程切换那样消耗资源。


存储

列举你所了解的计算机存储设备类型?

根据存储器在计算机系统中所起的作用,可分为主存储器、辅助存储器、高速缓冲存储器、控制存储器。

主存储器(内存, main memory):RAM和ROM,内存条。

辅助存储器(外存, external memory):软盘和硬盘,光盘,U盘。

高速缓冲存储器(cache): 集成在CPU内部。

控制存储器(CM): 只读,在CPU内。

区别:

内存只能暂存数据,外存可以永久性保存数据;

外存不受CPU控制,但外存必须借助内存才能与CPU交换数据;

内存访问速度快,外存访问速度慢。

参考:

基础-列举你所了解的计算机存储设备类型 - 简书

为什么需要虚拟内存?

虚拟内存是操作系统物理内存和进程之间的中间层,它为进程隐藏了物理内存这一概念,为进程提供了更加简洁和易用的接口以及更加复杂的功能。

虚拟内存的设计方法可以说是软件工程中的常见手段,通过结合磁盘和内存各自的优势,利用中间层对资源进行更合理地调度充分提高资源的利用率并提供和谐以及统一的抽象,而在实际的业务场景中,类似的缓存逻辑也比较常见。

操作系统的虚拟内存是非常复杂的组件,没有工程师能够了解其中的全部细节,不过了解虚拟内存的整体设计也很有价值,我们能够从中找到很多软件设计的方法。我们重新回到今天的问题 — Linux 操作系统中为什么需要虚拟内存:

  • 虚拟内存可以结合磁盘和物理内存的优势为进程提供看起来速度足够快并且容量足够大的存储;
  • 虚拟内存可以为进程提供独立的内存空间并引入多层的页表结构将虚拟内存翻译成物理内存,进程之间可以共享物理内存减少开销,也能简化程序的链接、装载以及内存分配过程;
  • 虚拟内存可以控制进程对物理内存的访问,隔离不同进程的访问权限,提高系统的安全性;

参考:

为什么 Linux 需要虚拟内存 - 面向信仰编程


字符编码

Unicode 和 UTF-8 之间的关系?

Unicode 是一种字符集合,现在可容纳 100 多万个字符。每个字符对应一个不同的 Unicode 编码,它只规定了符号的二进制代码,却没有规定这个二进制代码在计算机中如何编码传输。

UTF-8 是一种对 Unicode 的编码方式,它是一种变长的编码方式,可以用 1~4 个字节来表示 一个字符。

Unicode字符集有多种编码方式,如UTF-8、UTF-16、UTF-32等;ASCII只有一种;大多数MBCS(包括GB2312)也只有一种。

参考:

字符编码详解——彻底理解掌握编码知识,“乱码”不复存在-徐新华polaris-51CTO博客

原码、反码和补码的介绍

原码是计算机中对数字的二进制的定点表示方法,最高位表示符号位,其余位表示数值位。优点是易于分辨,缺点是不能够直接参与运算。 正数的反码和其原码一样;负数的反码,符号位为 1,数值部分按原码取反。

如 [+7]原 = 00000111,[+7]反 = 00000111; [-7]原 = 10000111,[-7]反 = 11111000。

正数的补码和其原码一样;负数的补码为其反码加 1。

例如 [+7]原 = 00000111,[+7]反 = 00000111,[+7]补 = 00000111; [-7]原 = 10000111,[-7]反 = 11111000,[-7]补 = 11111001 之所以在计算机中使用补码来表示负数的原因是,这样可以将加法运算扩展到所有的数值计算上, 因此在数字电路中我们只需要考虑加法器的设计就行了,而不用再为减法设置新的数字电路。

CPU

一般代码存储在计算机的哪个设备中?代码在 CPU 中是如何运行的?

执行之前,我们的代码​​主要​​存储在内存中。 CPU读取内存中的数据并放在寄存器内,将寄存器中的数据写入内存并进行有序的四则运算、相关指令,在此过程中,寄存器主要用于存放计算数据,运算器负责操作寄存器中的数据。

什么是指令,什么是指令集?

指令一般是指机器指令,是计算机可完成一个独立计算逻辑所要执行的的命令;一台常规的计算机的所有指令的集合,就是该计算机的指令集。