1 进程与线程

1.1 进程和线程的区别

  • 进程是资源分配基本单位,线程是资源调度的基本单位(对于无线程系统:进程是资源调度、分配的独立单位)
  • 线程依赖进程而存在
  • 进程有自己的独立地址空间,线程共享所属进程的地址空间
  • 进程是拥有系统资源的一个独立单位,而线程自己基本上不拥有系统资源,只有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)
  • 在进程切换时,涉及存储器管理方面的操作,开销比线程大

    1.2 进程有哪些状态

  • 就绪状态:进程已获得除处理机以外的所需资源,等待分配处理机资源

  • 运行状态:占用处理机资源运行,处于此状态的进程数小于等于CPU数
  • 阻塞状态: 进程等待某种条件,在条件满足之前无法执行

    1.3 进程间通信的手段

  • 管道(Pipe)

    • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道
    • 一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据
    • 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)
  • 命名管道
  • 消息队列
  • 信号(Signal)
  • 共享内存
  • 信号量(Semaphore):初始化操作、P操作、V操作;P操作:信号量-1,检测是否小于0,小于则进程进入阻塞状态;V操作:信号量+1,若小于等于0,则从队列中唤醒一个等待的进程进入就绪态
  • 套接字(Socket)

    1.4 僵尸进程

  • 概念:僵尸进程是一个已经死亡的进程,但是并没有真正被销毁。比如子进程结束后,父进程没有等待它(调用 wait 或 waitpid),那这个子进程就会变成僵尸进程 。

  • 危害:
    • 占用进程号
    • 占用内存(会在进程表中保留一个位置,记录进程号、终止状态、资源利用信息,供父进程收集)。
  • 如何处理:捕获SIGCHLD信号,并调用wait或waitpid

    1.5 孤儿进程

  • 概念:父进程结束了,它的子进程还在运行,这个子进程就是孤儿进程。

  • 孤儿进程会被init(进程ID为1)接管,孤儿进程结束时由init完成状态收集工作。

    1.6 多线程与多进程的对比、优劣、选择

    a. 对比

    | 对比维度 | 多进程 | 多线程 | 总结 | | —- | —- | —- | —- | | 数据共享、同步 | 数据共享复杂,需要用 IPC;
    数据是分开的,同步简单 | 因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂 | 各有优势 | | 内存、CPU | 占用内存多,切换复杂,CPU 利用率低 | 占用内存少,切换简单,CPU 利用率高 | 线程占优 | | 创建销毁、切换 | 创建销毁、切换复杂,速度慢 | 创建销毁、切换简单,速度很快 | 线程占优 | | 编程、调试 | 编程简单,调试简单 | 编程复杂,调试复杂 | 进程占优 | | 可靠性 | 进程间不会互相影响 | 一个线程挂掉将导致整个进程挂掉 | 进程占优 | | 分布式 | 适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单 | 适应于多核分布式 | 进程占优 |

b. 优劣

优劣 多进程 多线程
优点 编程、调试简单,可靠性较高 创建、销毁、切换速度快,内存、资源占用小
缺点 创建、销毁、切换速度慢,内存、资源占用大 编程、调试复杂,可靠性较差

c. 选择

  • 多线程:需要频繁创建销毁的、需要进行大量计算的、强相关的、可能要扩展到多核分布的,用多线程
  • 多进程:弱相关的、可能扩展到多机分布的,用多进程

    2 协程

    2.1 什么是协程

  • 协程是一种用户态的轻量级线程

    2.2 协程的特点

  • 协程的调度完全由用户控制

  • 有自己的寄存器上下文和栈
  • 协程调度切换时,将寄存器上下文和栈保存到其他地方,切回来的时候,恢复之前保存的寄存器上下文和栈(直接操作栈就基本没有内核切换的开销)
  • 可以不加锁的访问全局变量,上下文的切换非常快

    2.3 协程与线程/进程的比较

  • 进程和线程都可以拥有多个协程

  • 进程和线程是同步机制,协程是异步的
  • 协程能保留上一次调用时的状态

    3 Linux

    3.1 常用的Linux命令

  • 查看当前进程状态、杀死进程

    • ps -aux
    • kill

      4 堆栈区别[2]

  • 管理方式:栈由编译器自动管理,堆由开发者控制,容易产生内存泄漏。

  • 空间大小:在32位系统下,堆内存可以达到4G的空间(虚拟内存的大小,有面试官问过)。但对于栈来说,一般都是有一定的空间大小的(在VC6默认的栈空间大小是1M,也有默认2M的)。
  • 碎片问题:堆频繁new/delete会造成内存空间的不连续,造成大量的碎片,使程序效率降低(重点是如何解决?如内存池、伙伴系统等)。对栈来说不会存在这个问题,因为栈是先进后出,不可能有一个内存块从栈中间弹出。在该块弹出之前,在它上面的(后进的栈内容)已经被弹出。
  • 生长方向:堆向上生长(向着内存地址增加的方向);栈向下生长(向着内存地址减小的方向增长)
  • 分配方式:堆都是动态分配的,没有静态分配的堆。而栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,如局部变量分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器进行释放,无需我们手工实现。
  • 效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持(有专门的寄存器存放栈的地址,压栈出栈都有专门的机器指令执行),这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的(可以了解侯捷老师的内存管理的视频,关于malloc/realloc/free函数等)。例如分配一块内存,堆会按照一定的算法,在堆内存中搜索可用的足够大小的空间,如果没有(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。总之,堆的效率比栈要低得多

    5 死锁[1]

    5.1 什么是死锁

    多个并发进程中,每个进程持有某种资源又等待其他进程释放它们现在保持着的资源,没改变这个状态之前不能向前推进,这组进程就产生了死锁。

    5.2 产生死锁的必要条件

  • 互斥:一个资源一次只能被一个进程使用;

  • 占有并等待:一个进程至少占有一个资源,并在等待另一个被其它进程占用的资源;
  • 非抢占:已经分配给一个进程的资源不能被强制性抢占,只能由进程完成任务之后自愿释放;
  • 循环等待:若干进程之间形成一种头尾相接的环形等待资源关系,该环路中的每个进程都在等待下一个进程所占有的资源。

    5.3 处理方法

  • 鸵鸟策略

    • 死锁影响不大,或者概率很低,可以忽略死锁的情况。
  • 死锁预防 (破坏产生死锁的四个条件)
    • 破坏互斥:允许某些资源被多个进程同时访问
    • 破坏占有并等待:资源预先分配,或者申请资源前先释放占有的资源
    • 破坏非抢占:允许强制抢占
    • 破坏循环等待条件:对所有资源同一编号,所有进程对资源的请求按序号递增的顺序提出
  • 死锁避免
    • 银行家算法:动态检测资源分配状态,处于安全状态才能进行资源分配。(安全状态: 即使所有进程突然请求所需的资源,也能存在某种资源分配顺序,让每一个进程运行完毕 )
  • 死锁解除
    • 利用抢占:挂起进程并抢占其资源(要避免挂起时间过长而饥饿)
    • 利用回滚:让某些进程回退到可以解除死锁的情况,自动释放资源
    • 杀死某些进程知道死锁解除
  • 死锁的检测

    • 检查有向图是否存在环
    • 使用类似死锁避免的检测算法

      6 文件系统

      6.1 Windows 和 Linux 文件系统的区别[3]

  • Windows 中每个驱动器都有自己的根目录结构,多个文件树并列

  • Linux 只有一个文件树

    6.2 常见的文件系统格式

    a. Windows 文件系统[4]

  • FAT(File Allocation Table 文件配置表):适合做闪存、U 盘,单个文件最大 4 G

  • NTFS(New Technology File System 新技术文件系统):日志性的文件系统,同时管理员可以设置每个文件夹的访问权限,比较安全。
  • FAT64:适合做闪存,U 盘,移动硬盘。单个文件突破 4 G 的限制

    b. Linux 文件系统[5]

  • ext2,ext3

    • ext2 是为解决 ext 存在的缺陷而设计的,在速度和 CPU 利用率上有优势
    • ext3 是 ext2 的升级版,增加了日志记录。日志文件系统在断电或异常事件停机重启后,操作系统可以根据文件系统的日志,恢复到正常状态
  • swap 文件系统:用于 Linux 的交换分区
  • vfat:对 FAT 文件系统的统称
  • NFS:网络文件系统。用于在 UNIX 系统间通过网络进行文件共享,用户可以把 NFS 服务器提供的共享目录挂载在本地文件目录中,从而访问 NFS 文件系统的内容
  • F2FS:Flash 文件系统,针对 NAND 闪存存储介质做了友好设计

    6.3 自己写文件系统结构,要怎么写[7]

    a. 超级块 结构

  • 版本

  • 魔数
  • inode 个数
  • 数据块索引(为了简化文件块的定位)
  • padding(能被 4096 整除)

    b. inode 结构

  • inode 的模式(文件还是目录)

  • inode 的大小
  • 每个块的索引(定位文件)
  • padding

参考

  1. https://gitee.com/vict0r/Waking-Up/blob/master/Operating%20Systems.md (forked from https://github.com/wolverinn/Waking-Up
  2. https://www.nowcoder.com/discuss/588077?from=zhnkw
  3. https://blog.csdn.net/aixiangnan/article/details/89318735
  4. https://blog.csdn.net/hxxjxw/article/details/90136804
  5. https://www.cnblogs.com/xiaojianliu/articles/8545560.html
  6. http://blog.chinaunix.net/uid-28989651-id-3878690.html
  7. https://www.jianshu.com/p/8966d121263b?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation