此页内容

操作系统

9470字约32分钟

操作系统

!> 操作系统 面试题以及答案整理

进程 线程 协程

进程,线程,协程以及他们的区别

操作系统为了跟踪每个进程的活动状态,维护了一个进程表。进程表的内部列出了每个进程的状态以及每个进程使用的资源等。

进程:正在执行程序的一个实例,是资源分配的基本单位。(进程控制块(process control block)描述进程的基本信息和运行状态,所谓的创建和撤销进程,都是指对PCB的操作) 线程:进程中的单条流向,是程序独立调度的基本单位。

区别:

  1. (拥有资源)一个进程可以有多个线程,由于线程不拥有资源,这几个线程共享进程内的资源。
  2. (资源开销)创建和撤销线程比进程开销小很多,因为创建线程仅仅需要堆栈空间以及程序计数器就可以了而创建进程需要分配虚拟地址空间,数据资源等,开销比较大。
  3. (调度)由于线程是独立调度的基本单位,同一进程中线程的切换不会引起进程的切换,但是两个不同进程中的线程切换会引起进程切换。
  4. (通信)线程可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助IPC。
  5. 进程是资源分配的基本单位,线程是独立运行和独立调度的基本单位(CPU上真正运行的是线程)

如果问到为什么进程切换开销大:进程切换与线程切换的一个最主要区别就在于进程切换涉及到虚拟地址空间的切换而线程切换则不会。因为每个进程都有自己的虚拟地址空间,而线程是共享所在进程的虚拟地址空间的,因此同一个进程中的线程进行线程切换时不涉及虚拟地址空间的转换。

参考参考2参考3参考4参考5

线程和协程推荐在IO密集型的任务(比如网络调用)中使用,而在CPU密集型的任务中,表现较差。

上面的参考4做的笔记: 每个进程都有自己的虚拟地址空间,但是为了进一步保障系统运行安全,虚拟地址空间被划分为用户空间和内核空间,操作系统运行在内核空间,用户程序运行在用户空间,内核空间由所有进程的地址空间共享(所有进程的内核空间(3G-4G)都是共享的 属于所有进程。内核层共享,只是为了提供内核应该提供的访问接口。这样应用程序才能通过这些空间来和内核交互,以及调用其他功能和访问硬件。),但是用户程序不能直接访问内核空间,操作系统保存的进程控制信息自然是在内核空间,这里除了页目录以外还能找到很多重要的内容,例如进程和父进程ID,状态,打开文件句柄表等等

线程就是进程中的执行体,它要有指定的执行入口,通常是某个函数的指令入口,线程执行时要使用从进程虚拟地址空间中分配的栈空间来存储数据,这被称为线程栈,在创建线程时, 操作系统会在用户空间和内核空间分别分配两段栈,就是我们通常所说的用户栈和内核栈,线程切换到内核态执行时会使用内核栈,为的是不允许用户代码对其进行修改以保证安全,操作系统也会记录每个线程的控制信息(例如执行入口,线程栈,线程id),windows中线程控制信息对应TCB,在PCB中可以找到进程拥有的线程列表,同一个进程内的线程会共享进程的地址空间和句柄表等资源,而在linux中只使用了一个task_struct结构体,进程在创建子进程时会指定它和自己使用同一套地址空间和句柄表等资源,用这种方法来实现多线程的效果,

jDend6 -> OBSUxB -> fxNsLb -> BjNBU7 -> 4K7g2Y -> rpFLY1 -> z5MU89

如果接下来要执行进程A中的线程a1,执行入口如图所示在那里,cpu的指令指针就会指向线程的执行入口,当前执行用户空间的程序指令,所以栈基和栈指针寄存器会记录用户栈的位置,可以看到程序执行时,cpu面向的是某个线程,所以才说线程是操作系统调度和执行的基本单位,一个进程中至少要有一个线程,它要从这个线程开始执行,这被称为它的主线程,可以认为主线程是进程中的第一个线程,一般是由父进程或者操作系统创建的,而进程中的其他线程,一般都是由主线程创建的,

线程中发生函数调用时就会在线程栈中分配函数调用栈,而虚拟内存分配,文件操作,网络读写等很多功能,都是由操作系统来实现,再向用户程序暴露接口,所以,线程免不了要调用os提供的系统服务,也就是少不了进行系统调用,cpu中会有一个特权级标志,用户记录当前程序是在用户态还是内核态,只有标记为内核态时才可以访问内核空间,而目前线程a1处于用户态,还不能访问内核空间,所以系统调用发生时就得切换到内核态,使用线程的内核栈,执行内核空间的系统函数,这被称为从"用户态"切换到"内核态"。

最初系统调用是通过软中断触发的,所谓软中断,就是通过指令模拟中断,与软中断对应的是硬件中断,操作系统会按照cpu硬件要求,在内存里存一张中断向量表,用来把各个中断编号映射到相应的处理程序,例如Linux系统中,系统调用中断对应的编号为0x80,对应的处理程序就是用来派发系统调用的,为什么说派发系统调用呢?因为操作系统提供了数百个系统调用,不能为每一个都分配一个中断号,所以操作系统又实现了一张系统调用表,用于通过系统调用编号,找到对应的系统函数入口,所以用户程序这里,会把要调用的系统函数编号存入特定寄存器,通过寄存器或用户栈来传递其他所需参数,然后用int 0x80来触发系统调用中断,而硬件层面,CPU有一个中断控制器,它负责接收中断信号,切换到内核态,保存用户态执行现场,一部分寄存器的值会通过硬件机制保存起来,还有一部分通用寄存器的值,被压入内核栈中,然后去中断向量表这里查询0x80对应的系统调用派发程序入口,而系统调用的派发程序会根据指定的系统调用编号,去系统调用表这里查询对应的系统调用入口并执行,后来为了优化系统调用的性能,改为通过特殊指令触发系统调用,例如x86的sysenter,和amd64平台下的syscall,当cpu执行到这些指令时就会陷入内核态,从专用寄存器拿到派发入口的地址,省去了查询中断向量表的过程,等系统调用结束后,再利用之前保存的信息,恢复现场在用户态的执行现场,继续执行后面的指令,这样就完成了一次系统调用。ok,对线程的调用有一个大致了解。

EOZqYs

接下来就可以看看线程切换是怎么回事了? 我们知道现代操作系统中,cpu的执行权被划分为不同的时间片,只有获得cpu时间片的程序才可以运行,由于时间片很短,所以用户感觉不到程序的切换过程,又因为cpu很快,所以即使很短的时间片,也足够它执行很多很多的指令,一个线程获得的时间片用完时,cpu硬件时钟会触发一次时钟中断,对应的中断处理程序,会从已经就绪的线程中挑选一个来执行,我们暂不展开线程调度的问题,只关注切换过程。 例如接下来要从线程a1切换到线程a2,这两个线程同属于进程A,那么这就涉及到线程切换,ZGnbNl 只需要把线程a1的执行现场保存起来,后续再把指令指针,栈指针这些寄存器的值,修改为线程a2的信息,修改一下内存中调度相关的数据结构,一次同进程间的线程切换就算完成了。

MAiBJ8 -> 64R8Kv

等到线程a1再次获得时间片之后,会根据之前保存的信息,恢复到切换前的执行现场,继续完成它的任务,假如线程a1要切换到另一个进程B的线程b1,那么除了线程切换外还有涉及到进程切换,cpu这里保存的页目录地址要切换到进程B,所以进程切换与线程切换的区别就是进程切换会导致地址空间等进程资源发生变化,会导致TLB缓存失效,代价相应的会更大。 WKJXR1 -> 6dCq7x

到目前为止,我们已经了解了进程和线程的结构,(如下图所示) Eqwwvs 理解了线程的用户栈和内核栈,(如下图所示) S0d8KU

以及进程切换与线程切换的大致过程,(如下图所示) WKJXR1 -> 6dCq7x

不过时间片轮转也只是触发进程或线程切换的多种场景之一,

6ZmMEq

进程与线程区别

  1. 进程是资源分配的基本单位,线程是独立运行和独立调度的基本单位(CPU上真正运行的是线程)
  2. 进程拥有自己的资源空间,一个进程包含若干个线程,线程与CPU资源分配无关,多个线程共享同一进程内的资源
  3. 线程的调度与切换比进程快很多

线程和协程推荐在IO密集型的任务(比如网络调用)中使用,而在CPU密集型的任务中,表现较差。

进程之间如何通信

进程间通信:(Inter process communication) 几种方式:

  1. 消息队列:消息队列是内核中存储消息的链表,它由消息队列标识符进行标识,这种方式能够在不同的进程中间提供全双工通信连接

  2. 管道:用于两个相关进程间通信,是一种半双工的通信方式,只能在父子进程中使用,如果需要全双工,需要另外的一个管道。

  3. 套接字:与其他通信方式不同,可以用于不同机器之间的进程通信。

  4. 信号量:是一个计数器,用于为多个进程提供对共享数据对象的访问

  5. 共享内存:使用所有进程的内存来建立连接,不过需要同步进程(信号量)来保护访问。是最快的IPC方式。

  6. 消息传递:消息传递是进程间实现通信和同步等待的机制。消息直接由发送方传递给接收方。

  7. 管道/匿名管道(Pipes) :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。

  8. 有名管道(Names Pipes) : 匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道。有名管道严格遵循先进先出(first in first out)。有名管道以磁盘文件的方式存在,可以实现本机任意两个进程通信。

  9. 信号(Signal) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;

  10. 消息队列(Message Queuing) :消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显示地删除一个消息队列时,该消息队列才会被真正的删除。消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比 FIFO 更有优势。消息队列克服了信号承载信息量少,管道只能承载无格式字 节流以及缓冲区大小受限等缺。

  11. 信号量(Semaphores) :信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件。

  12. 共享内存(Shared memory) :使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。可以说这是最有用的进程间通信方式。

  13. 套接字(Sockets) : 此方法主要用于在客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

  14. 远程过程调用(RPC)

  15. 类似问题: 无名管道,命名管道,共享内存,消息队列,套接字(分别有哪些例子)

  16. 类似问题:进程间怎样通信

  17. 参考

  18. JavaGuide

进程的生命周期

  1. 创建状态:系统已为其分配了PCB,但进程所需资源尚未分配,进程还未进入主存,即创建工作尚未完成,进程还不能被调度运行。
  2. 就绪状态:进程已分配到除CPU以外打的所有必要资源,等待获得CPU。
  3. 执行状态:进程已获得CPU,程序正在执行。
  4. 阻塞状态:正在执行的进程由于某事件而暂时无法继续执行时,放弃处理机而自行阻塞。
  5. 终止状态:进程到达自然结束点或者因意外被终结,将进入终止状态,进入终止状态的进程不能再执行,但在操作系统中仍然保留着一个记录,其中保存状态码和一些计时统计数据,供其它进程收集。

进程调度

背景:当两个或两个以上的进程/线程处于就绪状态时,如果只有一个CPU可用,那么必须选择接下来哪个进程/线程可以运行,操作系统中有一个叫做调度程序(scheduler)的角色存在就是做这件事的。

不同的系统中,调度算法是不同的,有如下3种情况:

  1. 批处理

    1. 先来先服务
    2. 最短作业有限
    3. 最短剩余时间优先
  2. 交互式

    1. 轮询调度(时间片轮转调度算法 )
    2. 优先级调度
    3. 多级队列
    4. 最短进程优先
    5. 保证调度
    6. 彩票调度
    7. 公平分享调度
  3. 实时

    1. 单比率调度
    2. 限期调度
    3. 最少裕度法
  4. 参考自己的os打印的那个笔记书

  5. 参考

  6. 参考

并发与并行

并发:在操作系统中,某一时间段,几个程序在同一个CPU上运行,但在任意一个时间点上,只有一个程序在CPU上运行。

并行:当操作系统有多个CPU时,一个CPU处理A线程,另一个CPU处理B线程,两个线程互相不抢占CPU资源,可以同时进行,这种方式成为并行。

注意点:并发的关键是你有处理多个任务的能力,不一定要同时。并行的关键是你有同时处理多个任务的能力。所以我认为它们最关键的点就是:是否是『同时』

一个让人更加容易理解的例子:

  1. 你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
  2. 你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
  3. 你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。

线程共享的有什么,不共享的有什么

共享的资源有:

  1. 堆。 由于堆是在进程空间中开辟出来的,所以它是理所当然地被共享的;因此new出来的都是共享的(16位平台上分全局堆和局部堆,局部堆是独享的)
  2. 全局变量 。它是与具体某一函数无关的,所以也与特定线程无关;因此也是共享的
  3. 静态变量。 虽然对于局部变量来说,它在代码中是“放”在某一函数中的,但是其存放位置和全局变量一样,存于堆中开辟的.bss和.data段,是共享的
  4. 文件等公用资源。 这个是共享的,使用这些公共资源的线程必须同步。Win32 提供了几种同步资源的方式,包括信号、临界区、事件和互斥体。

独享的资源有:

  1. 栈 。栈是独享的
  2. 寄存器 。 这个可能会误解,因为电脑的寄存器是物理的,每个线程去取值难道不一样吗?其实线程里存放的是副本,包括程序计数器PC

参考

孤儿进程的区别,如何解决孤儿进程的出现

参考:https://blog.cugxuan.cn/2020/07/07/Linux/a-bug-to-learn-orphan-and-zombie/

Unix进程模型中,进程是按照父进程产生子进程,子进程产生子子进程这样的方式创建出完成各项相互协作功能的进程的。当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。如果父进程没有这么做的话,会产生什么后果呢?此时,子进程虽然已经退出了,但是在系统进程表中还为它保留了一些退出状态的信息,如果父进程一直不取得这些退出信息的话,这些进程表项就将一直被占用,此时,这些占着茅坑不拉屎的子进程就成为“僵尸进程”(zombie)。系统进程表是一项有限资源,如果系统进程表被僵尸进程耗尽的话,系统就可能无法创建新的进程。

那么,孤儿进程又是怎么回事呢?孤儿进程是指这样一类进程:在进程还未退出之前,它的父进程就已经退出了,一个没有了父进程的子进程就是一个孤儿进程(orphan)。既然所有进程都必须在退出之后被wait()或waitpid()以释放其遗留在系统中的一些资源,那么应该由谁来处理孤儿进程的善后事宜呢?这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程“凄凉地”结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。这样来看,孤儿进程并不会有什么危害,真正会对系统构成威胁的是僵尸进程。那么,什么情况下僵尸进程会威胁系统的稳定呢?设想有这样一个父进程:它定期的产生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是,父进程只管生成新的子进程,至于子进程退出之后的事情,则一概不闻不问,这样,系统运行上一段时间之后,系统中就会存在很多的僵尸进程,倘若用ps命令查看的话,就会看到很多状态为Z的进程。严格地来说,僵尸进程并不是问题的根源,罪魁祸首是产生出大量僵尸进程的那个父进程。因此,当我们寻求如何消灭系统中大量的僵尸进程时,答案就是把产生大量僵尸进程的那个元凶枪毙掉(通过kill发送SIGTERM或者SIGKILL信号)。枪毙了元凶进程之后,它产生的僵尸进程就变成了孤儿进程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经“僵尸”的孤儿进程就能瞑目而去了。

  1. 参考

了解锁么,如何实现一个锁

上层协程结束了,如果通知到子协程也结束

用户态和内核态

线程的上下文切换

内核态线程和用户态线程的区别如何切换

上下文切换的细节

fork之后的父子进程虚拟内存空间的相同与不同

多线程中会对全局变量进行pad操作,请问是为啥?

面试官解释说是padding操作,也就是struct中的内存对其那种

一个线程是如何被挂起的

一个进程是如何被挂起的

线程之间的通信方式

进程池 线程池

上下文切换的细节

内核态线程和用户态线程的区别如何切换

多线程线程的弊端

线程的上下文切换

用户态和内核态

什么是线程安全

参考

进程、线程究竟是由什么组成的?有哪些数据?

进程调度算法


IO模型

IO和多路复用

epoll的底层实现

io多路复用的类别

Io模型

select、epoll

Epoll


死锁

死锁一般发生在多线程(两个或两个以上)执行的过程中。因为争夺资源造成线程之间相互等待,这种情况就产生了死锁。我在 06 讲也提到了死锁,但是并没有讲它产生的原因以及怎么避免,所以接下来我们就来了解这部分内容。 案例:sylQm6 比如你有资源 1 和 2,以及线程 A 和 B,当线程 A 在已经获取到资源 1 的情况下,期望获取线程 B 持有的资源 2。与此同时,线程 B 在已经获取到资源 2 的情况下,期望获取现场 A 持有的资源 1。

那么线程 A 和线程 B 就处理了相互等待的死锁状态,在没有外力干预的情况下,线程 A 和线程 B 就会一直处于相互等待的状态,从而不能处理其他的请求。

死锁产生的四个必要条件

  1. 互斥:多个线程不能同时使用一个资源。比如线程 A 已经持有的资源,不能再同时被线程 B 持有。如果线程 B 请求获取线程 A 已经占有的资源,那线程 B 只能等待这个资源被线程 A 释放。GNLKGG
  2. 持有并等待:当线程 A 已经持有了资源 1,又提出申请资源 2,但是资源 2 已经被线程 C 占用,所以线程 A 就会处于等待状态,但它在等待资源 2 的同时并不会释放自己已经获取的资源 1。Bd1uMr
  3. 线程 A 获取到资源 1 之后,在自己使用完之前不能被其他线程(比如线程 B)抢占使用。如果线程 B 也想使用资源 1,只能在线程 A 使用完后,主动释放后再获取。VDvJKe
  4. 发生死锁时,必然会存在一个线程,也就是资源的环形链。比如线程 A 已经获取了资源 1,但同时又请求获取资源 2。线程 B 已经获取了资源 2,但同时又请求获取资源 1,这就会形成一个线程和资源请求等待的环形图。WK1SdF

并发场景下一旦死锁,一般没有特别好的方法,很多时候只能重启应用。因此,最好是规避死锁,那么具体怎么做呢?答案是:至少破坏其中一个条件(互斥必须满足,你可以从其他三个条件出发)。

持有并等待:我们可以一次性申请所有的资源,这样就不存在等待了。

不可剥夺:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源,这样不可剥夺这个条件就破坏掉了。

循环等待:可以靠按序申请资源来预防,也就是所谓的资源有序分配原则,让资源的申请和使用有线性顺序,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样的线性化操作就自然就不存在循环了。

四种处理死锁的策略

  1. 忽略死锁带来的影响:鸵鸟算法
  2. 检测死锁并恢复死锁,死锁发生的时候对其进行检测,一旦发生死锁,采取行动解决问题。
    • 检测:
      1. 每当有资源请求就去检测,会占用昂贵的CPU时间
      2. 每隔k分钟检测一次,或者当cpu利用率降低到某个标准下去检测。
    • 恢复:
      • 通过抢占恢复
      • 通过回滚恢复
      • 杀死进程恢复
  3. 通过仔细分配资源来避免死锁
    • 单个资源的银行家算法
  4. 通过破坏死锁产生的4个条件之一来避免死锁
    • 破坏互斥
    • 破坏循环等待
    • 破坏保持等待
    • 不可抢占

操作系统死锁的问题

死锁以及怎样避免

死锁的必要条件

死锁的预防

死锁的处理策略(死锁预防、死锁检测与恢复、死锁避免)


内存

了解虚拟内存吗?什么是虚拟内存?为什么要有虚拟内存?

mmu有了解吗? 讲讲mmu

内存分页的目的是什么?

内存管理,包括:虚拟内存(重点)、分页、分段、分页系统地址映射、内存置换算法(重点)。

页面置换算法

常用的是如下4种:

  1. OPT 页面置换算法(最佳页面置换算法) :最佳(Optimal, OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。一般作为衡量其他置换算法的方法。
  2. FIFO(First In First Out) 页面置换算法(先进先出页面置换算法) : 总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
  3. LRU (Least Currently Used)页面置换算法(最近最久未使用页面置换算法) :LRU算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 T,当须淘汰一个页面时,选择现有页面中其 T 值最大的,即最近最久未使用的页面予以淘汰。
  4. LFU (Least Frequently Used)页面置换算法(最少使用页面置换算法) : 该置换算法选择在之前时期使用最少的页面作为淘汰页。

完整的列表:FCbIT4

虚拟内存是什么

后面的问题:内存每次从磁盘换页进来的效率很低,如何优化?

后面的问题:一个大型游戏,哪些数据要加载到内存,哪些数据要存放在磁盘


其他

操作系统组成

进程管理,文件管理,内存管理,设备管理,

CPU密集型(CPU-bound)与 IO密集型(I/O bound)

CPU密集型(CPU-bound)

  1. CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/内存),I/O在很短的时间就可以完成,而CPU还有许多运算要处理,CPU Loading很高。
  2. 在多重程序系统中,大部份时间用来做计算、逻辑判断等CPU动作的程序称之CPU bound。例如一个计算圆周率至小数点一千位以下的程序,在执行的过程当中绝大部份时间用在三角函数和开根号的计算,便是属于CPU bound的程序。
  3. CPU bound的程序一般而言CPU占用率相当高。这可能是因为任务本身不太需要访问I/O设备,也可能是因为程序是多线程实现因此屏蔽掉了等待I/O的时间。

IO密集型(I/O bound)

  1. IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。
  2. I/O bound的程序一般在达到性能极限时,CPU占用率仍然较低。这可能是因为任务本身需要大量I/O操作,而pipeline做得不是很好,没有充分利用处理器能力。
  3. 计算密集型任务需要大量的计算,虽然多任务也可以完成计算密集型任务,但是任务越多花在任务切换时间越多,CPU执行任务的效率越低,所以要高效利用CPU,采用多进程开发。
  4. IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因此,用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言,完全无法提升运行效率(原因就是因为计算不是短板,IO是短板,所以提高IO才会显著提升性能)。对于IO密集型任务,最合适的语言就是开发效率最高(代码量最少)的语言,脚本语言是首选,C语言最差。

总结:CPU密集型任务使用多进程,IO密集型任务使用多线程

内存泄漏与内存溢出:

  1. 2SMulF
  2. AlhrJW
  3. tmwKDK

阻塞与非阻塞

  1. 阻塞是指调用线程或者进程被操作系统挂起。
  2. 非阻塞是指调用线程或者进程不会被操作系统挂起。

同步与异步

同步是阻塞模式,异步是非阻塞模式。

同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,知道收到返回信息才继续执行下去; 异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回式系统会通知进程进行处理,这样可以提高执行的效率。 由调用方盲目主动问询的方式是同步调用,由被调用方主动通知调用方任务已完成的方式是异步调用。看下图

参考

堆 栈 区别

操作系统中的锁

socket的概念

磁盘转一次要多久

CPU负载过高了怎么办,问题定位

磁盘寻道算法

程序执行的交互过程,CPU,OS,内存和磁盘都要涉及。

LinuxIO 的原理,具体 IO 过程介绍。

临时变量存放在哪里?

执行代码存放在哪里?

虚拟内存是什么?

内存每次从磁盘换页进来的效率很低,怎么优化?

同步 IO 和异步 IO

5、 进程和线程的区别,创建线程和进程的开销指什么

6、 死锁及如何避免

计算机为什么要用补码?

  1. 计算机内部的存储结构?虚拟内存和物理内存的区别?

  2. 多进程和多线程的区别

进程间的通信,文件通信了解过么?线程间共享的有哪些东西?

操作系统你了解多少,你最常用的系统是哪个,对 shell 命令熟悉吗,如何查看内存和 cpu 使用情况

3.进程和线程的区别

4.进程间有哪些通信方式,如果有两个进程,一个进程执行一半要求另一个进程终止,该 如何操作

linux shell 中按下 ctrl+c 会怎么样,为什么?(发送信号使进程退出)

内核态与用户态区别(记不清了,于是 balabala…提到了通过系统调用与中断来进入内核 态…)

软中断与硬中断(硬中断记得是外设硬件产生,软中断记不得了……)

如何防止密码被 hash 碰撞攻击(加盐,但是我只记得个名字了,内容与***作忘了……)

为什么扫二维码可以实现登录(妈呀这啥)

3.线程和进程之间哪个快,有什么区别

interrupt 与 signal 有什么差别

interrupt 的发起和接受者是谁

操作系统在 interrupt 中发挥了什么作用

signal 呢,发起者又是谁,接收者呢?(这里答得有点混乱)

进程地址空间布局讲一下

BSS 为什么要叫这个名字?(后来查了,block started by symbol)

一个进程,有 10 个子进程,那么一个子进程 fork 一个子进程,那么这个子进程 有多少个进程。

物理地址和虚地址

buffer 和 cacahe 区别

CPU 有哪些组成,你怎么设计一个 CPU?CPU 调度算法有哪些?

虚拟内存是什么,分段分页是啥?

编译有哪些阶段?

信号量 PV 原语写个生产者消费者模型,父亲生产苹果,母亲生产橘子,盘子里面只能放 一个水果,儿子只吃苹果,女儿只吃橘子

问一个数据是怎么写到磁盘上去的,我就随便答了下

线程之间的通信(我回答成了进程之间的,后来又强行答了一波)

linuxIO 模型,区别在哪

线程独立拥有哪些资源

协程和线程有什么差别,优势呢?

贡献者: cvenwu

No Pains, No Gains