常见问题

全是从面经里扒拉出来的面试题

进程和线程

进程:资源分配的基本单位,一个进程中可以有多个线程,它们共享进程资源,线程不拥有资源,线程可以访问隶属进程的资源。

线程:独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换。

  • 系统开销 由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,所付出的开销远大于创建或撤销线程时的开销。

    • 类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置。

    • 而线程切换时只需保存和设置少量寄存器内容,开销很小。

  • 通信方面 线程间可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助 IPC

  • 为什么有进程还要线程:减少程序在并发执行时所付出的时空开销,提高并发性。

进程间通信

类似问题:

  • 操作系统中有哪些跨进程通信(IPC)的方法

📌进程通信

进程通信的种方式:管道、FIFO、消息队列、信号量、共享存储、套接字。

管道:速度慢,容量有限,只有父子进程能通讯。管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

FIFO:任何进程间都能通讯,但速度慢。FIFO是一种半双工的通信方式,但是它允许无亲缘关系进程间的通信。

消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题。消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

信号量:不能传递复杂消息,只能用来同步。信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段

共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存。

共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

套接字Socket:套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

消息队列对比管道、FIFO的优点:

  • 消息队列可以独立于读写进程存在,从而避免了 FIFO 中同步管道的打开和关闭时可能产生的困难;

  • 避免了 FIFO 的同步阻塞问题,不需要进程自己提供同步方法;

  • 读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收。

进程同步

📌进程同步

  • 进程同步:控制多个进程按一定顺序执行

  • 进程通信:进程间传输信息

线程通信

方式一:使用 volatile 关键字。使用共享内存的思想,大致意思就是多个线程同时监听一个变量,当这个变量发生变化的时候 ,线程能够感知并执行相应的业务。这也是最简单的一种实现方式。

方式二:使用 Object 类的wait()、notify() 和 notifyaAlL(),它们是多线程通信的基础,而这种实现方式的思想自然是线程间通信。

注意:wait() 和 notify() 必须配合 synchronized 使用。

调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。它们都属于 Object 的一部分,而不属于 Thread。只能用在同步方法或者同步控制块中使用,否则会在运行时抛出IllegalMonitorStateException。使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁。

线程安全

Java

保证线程安全可从多线程三特性出发:

原子性(Atomicity):单个或多个操作是要么全部执行,要么都不执行

  • Lock:保证同时只有一个线程能拿到锁,并执行申请锁和释放锁的代码

  • synchronized:对线程加独占锁,被它修饰的类/方法/变量只允许一个线程访问

原子性就是说一个操作不可以被中途cpu暂停然后调度即不能被中断,要不就执行完,要不就不执行。如果一个操作是原子性的,那么在多线程环境下,就不会出现变量被修改等奇怪的问题。

可见性(Visibility):当一个线程修改了共享变量的值,其他线程能够立即得知这个修改

  • volatile:保证新值能立即同步到主内存,且每次使用前立即从主内存刷新;

  • synchronized:在释放锁之前会将工作内存新值更新到主存中

有序性(Ordering):程序代码按照指令顺序执行

  • volatile: 本身就包含了禁止指令重排序的语义

  • synchronized:保证一个变量在同一个时刻只允许一条线程对其进行lock操作,使得持有同一个锁的两个同步块只能串行地进入

一定有线程吗?为什么要有线程?

类似问题:

  • 操作系统一定有线程吗?

  • 为什么要有线程

请你说一说有了进程,为什么还要有线程?

谈谈对操作系统中的进程的理解

线程和进程的同步机制和通信机制

进程的内存布局,哪些是线程共享

进程与线程的切换开销

进程同步

进程调度算法

进程调度的策略,现在的OS主要是什么策略

进程内部和进程之间如何处理同一个文件

线程调度的方式

什么是缓存溢出

并发和并行分别是什么意思,多线程是并发还是并行

单CPU能实现多任务并行吗

CPU 调度算法

类似问题:

  • CPU 调度算法,多核的情况下,操作系统怎么处理

为什么有多进程也有多线程

扯到了虚拟内存空间,面试官就问为什么要这样设计?解决什么问题?

操作系统的内存管理

分页分段段页式

虚拟内存和物理内存的区别

假如手机只有10M内存,想要申请1M的内存是否一定成功

内存分布

什么是虚拟内存、共享内存、物理内存

虚拟内存的作用

说说共享内存的原理

分页分段管理

分段和分页有什么区别

页一般多大

中断

类似问题:

  • 中断是什么,Linux的中断命令

  • 中断是怎么实现的

  • linux 崩溃中断

  • 解释一下中断

操作系统有哪些算法支持高效的内存的申请与释放,同时最大化的减少碎片

zero-copy 与 copy-on-write(COW);

地址空间的概念

指针能不能访问0x0

如何在进程中直接操作物理地址

计算机寻址的方式

直接寻址和间接寻址谁更安全

为什么要分用户态、内核态

类似问题:

  • 用户态/内核态

  • 内核态、用户态相关,扯了几句异常控制流

时间片

4个CPU,16个数,每个CPU每次只能比较一次两个数的大小,只能返回truefalse,互相之间不能通信,一轮以时间片为单位,需要几轮能够找出最大的数(4个CPU与4个数,可以一轮就找到最大的数吗)

死锁以及如何避免死锁

类似问题:

  • 死锁的四个条件,开发过程中什么情况容易造成死锁

多线程访问堆段会出现什么问题,如何解决这些问题

(信号量、锁)

堆和栈的区别

生产者-消费者模型,其中的同步机制是怎么样的

读者写者模型

类似问题:

  • 读者-写者问题

什么是抢占

程序崩溃

多线程会不会导致程序崩溃,程序会因为什么崩溃,子线程崩了的话进程会不会崩?(如果捕获了异常或信号就不会崩)

什么情况下会stackoverflow

操作系统的锁底层如何实现

知道哪些锁,说说它们的区别

什么是互斥锁/读写锁

类似问题:

  • 什么场景用互斥锁,什么场景用读写锁

文件I/O的过程

什么是写优先和读写平衡

大小端

最后更新于