浅学操作系统:进程

2023-11-20 20:41:39 浏览数 (1)

操作系统

1. 进程 线程 协程关系与区别

进程(Process)与线程(Thread)与协程(Coroutine)

  1. 进程: 程序是⼀些保存在磁盘上的指令的有序集合,是静态的。进程是程序执⾏的过程,包括了动态创建、调度和消亡的整个过程,进程是程序资源分配管理的最⼩单位
  2. 线程: 线程是操作操作系统能够进⾏运算调度的最⼩单位。线程被包含在进程之中,是进程中的实际运作单位,⼀个进程内可以包含多个线程,线程是资源调度的最⼩单位
  3. 进程和线程的关系:可以把进程想成现实生活中的公司,公司可以给员工提供办公资源(办公桌椅,办公电脑等资源),真正干活的是员工,所以员工可以想成线程,公司就是进程。
  4. 协程: 协程是用户态的轻量级线程,不受操作系统的调度,而是由程序员或者库来控制。协程可以在⼀个线程中切换执⾏多个任务,实现了异步编程的效果。协程的创建和销毁完全由用户空间完成,开销非常小。 特点:
    1. 线程的切换由操作系统负责调度,协程由用户自己进行调度,因此减少了上下文切换,提高了效率。
    2. 线程的默认Stack大小是1M,而协程更轻量,接近1K。因此可以在相同的内存中开启更多的协程。
  5. 线程和协程的区别:协程内存占用小,创建和销毁消耗小,协程之间切换的代价小。

三者的区别

  1. 资源分配:进程是资源分配的单位,线程和协程是资源调度的单位。
  2. 地址空间:进程有独⽴的地址空间,线程共享进程的地址空间,协程也共享所在线程的地址空间。
  3. 调度⽅式:进程和线程由操作系统调度,协程由⽤⼾或者库调度。
  4. 开销大小:进程的开销最⼤,线程次之,协程最⼩。

2. 什么是并发,什么是并行

  1. 并发: 多个任务在同⼀个时间段内交替进⾏,通过不断地切换上下⽂来实现同时执⾏的效果。 任务数大于cpu的核数,多个任务轮流执行,由于cpu切换速度特别快,看起来像是一起运行,其实是假象。
  2. 并行: 多个任务在同⼀个时间段内实际同时执⾏,并利⽤多个处理器或多核CPU的并⾏计算能⼒ 来加速任务的完成。 任务数小于或者等于cpu的核数,那么多个任务是真正意义一起执行。

3. 进程间的同步方式和通信方式有哪些?

进程之间的同步方式:

  1. 临界区(Critical Section):通过对共享资源设置访问限制,使得同⼀时间只能有⼀个进程访问共 享资源,从⽽避免多个进程同时访问共享资源导致的数据不⼀致性问题。
  2. 互斥量(Mutex):通过对共享资源设置互斥锁,使得同⼀时间只有⼀个进程能够获取该锁,从⽽避免多个进程同时访问共享资源导致的数据不⼀致性问题。
  3. 信号量(Semaphore):通过对共享资源设置信号量,使得进程可以通过信号量来协调对共享资源的访问,从⽽避免多个进程同时访问共享资源导致的数据不⼀致性问题。
  4. 事件(Event):通过对事件的状态进⾏监控,使得进程可以在事件状态发⽣变化时得到通知,从 ⽽协调进程之间的操作。

进程间的通信方式:

  1. 管道(Pipe):管道是⼀种单向通信⽅式,可以在进程间传输数据。管道只能⽤于⽗⼦进程之间或 者兄弟进程之间的通信。
  2. 命名管道(Named Pipe):命名管道是⼀种单向通信⽅式,可以在进程间传输数据。与管道不同 的是,命名管道可以⽤于任意进程之间的通信。
  3. 共享内存(Shard Memory):共享内存是⼀种通过共享内存块的⽅式进⾏进程间通信的⽅式。 多个进程可以访问同⼀个共享内存区域,并可以在该区域中进⾏数据读写。
  4. 信号(Signal):信号是⼀种异步通信⽅式,进程可以通过发送信号来通知其他进程或者处理特定事件。
  5. 消息队列(Message Queue):消息队列是⼀种通过消息传递的⽅式进⾏进程间通信的⽅式。多个进程可以通过消息队列来发送和接收消息。
  6. 套接字(Socket):套接字是⼀种通过⽹络进⾏进程间通信的⽅式。进程可以通过套接字进⾏数据 的发送和接收。

4. 线程间的同步方式

在线程间实现同步是为了确保多个线程按照特定的顺序执⾏,以避免竞态条件(race condition)和其 他并发问题。以下是常⻅的线程间同步⽅式:

  1. 互斥锁(Mutex):互斥锁是最常⽤的同步机制之⼀。⼀个互斥锁只能同时被⼀个线程获取,其他线程必须等待该线程 释放锁后才能继续执⾏。互斥锁⽤于保护临界区(Critical Section),确保只有⼀个线程可以访问 共享资源。
  2. 信号量(Semaphore): 信号量是⼀个计数器,⽤于控制对共享资源的访问。它可以允许多个线程同时访问资源,但是要限 制同时访问的线程数量。信号量可以⽤来实现资源池的管理等场景。
  3. 条件变量(Condition Variable): 条件变量⽤于在线程间实现条件等待和通知。⼀个线程可以等待某个条件成⽴,当条件满⾜时,另 ⼀个线程可以通知等待的线程继续执⾏。条件变量通常和互斥锁⼀起使⽤,以确保在等待条件时不 会出现竞态条件。
  4. 读写锁(Read-Write Lock): 读写锁允许多个线程同时读取共享资源,但在有线程在写⼊时,其他线程不能进⾏读或写操作。这 样可以提⾼读操作的并发性能,适⽤于读多写少的场景。
  5. 屏障(Barrier): 屏障⽤于将多个线程分为多个阶段执⾏,在每个阶段的某个点上,所有线程必须等待,直到所有线 程都到达屏障点,然后继续执⾏下⼀个阶段。
  6. 原⼦操作: 原⼦操作是⼀种不可被中断的操作,要么完全执⾏成功,要么完全不执⾏,不存在中间状态。原⼦ 操作可以⽤于简单的同步需求,如增加或减少共享变量的值,确保在多线程环境下数据的⼀致性。

5. 进程有哪些状态

  1. 新建状态(New):进程刚被创建,但尚未被调度执⾏。
  2. 就绪状态(Ready):进程已经准备好运⾏,但尚未被分配到CPU资源。
  3. 运⾏状态(Running):进程正在运⾏,占⽤CPU资源。
  4. 阻塞状态(Blocked):进程因为某些原因(⽐如等待I/O操作完成)⽽暂时⽆法运⾏,在这个状态 下,进程不会占⽤CPU资源。
  5. 终⽌状态(Terminated):进程已经完成了执⾏或者被操作系统强制终⽌。

6. 进程如何被调度

调度的方式

  1. 非剥夺调度方式/非抢占方式 即只允许进程主动放弃CPU。在运⾏过程中即便有更紧迫的任务到达,当前进程依然会继续使⽤处理机,直到该进程终⽌或主动要求进⼊阻塞态。
  2. 剥夺调度方式/抢占方式 当⼀个进程正在处理机上执⾏时,如果有⼀个更重要或更紧迫的进程需要使⽤处理机,则⽴即暂停正在执⾏的进程,将处理机分配给更重要紧迫的那个进程。

7. 常见的调度机制有什么

  1. 先来先服务 (First-Come, First-Served, FCFS)
    • 非抢占式的调度算法
    • 每次从就绪队列选择最先进入队列的进程,然后⼀直运行, 直到进程退出或被阻塞,才会继续从队列中选择第⼀个进程接着运行。
    • 适用于无需考虑执行时间的简单场景,但可能长作业或进程可能导致其他短作业或进程的等待时间过长,产生"饥饿"现象。
  2. 最短作业优先 (Shortest Job Next, SJN):
    • 非抢占式的调度算法
    • 选择估计执行时间最短的进程优先执行,以减少平均等待时间。
    • 需要准确估计执行时间,可能导致长作业优先,产生"饥饿"现象。
  3. 最短剩余时间优先 (Shortest Remaining Time Next, SRTN)
    • 抢占式的调度算法,最短作业优先的抢占式版本
    • 当⼀个新的作业到达时,其整个运行时间与当前进程的剩余时间作比较。如果新的进程需要的时间更少,则挂起当前进程,运行新的进程。否则新的进程等待。
    • 需要动态估计剩余执行时间,可能导致长作业或进程的等待时间过长,产生"饥饿"现象。
  4. 高响应比优先:
    • 非抢占式的调度算法
    • 响应比=等待时间/服务时间,响应比高的先执行,可以避免饥饿现象。(1,2⽅式的平衡实现)
  5. 时间片轮转调度 (Round Robin, RR):
    • 抢占式的调度算法
    • 给每个进程都分配⼀个时间片,时间片执行完毕就会切换进程,执行下⼀个进程,依次循环。
    • 公平,但容易频繁的切换进程,浪费系统资源。
  6. 优先级调度 (Priority Scheduling):
    • 有抢占式也有非抢占式
    • 为每个进程分配一个优先级,根据优先级的高低来决定执行顺序。
    • 抢占式是动态调整优先级,如按照运行时间调整优先级非;抢占式是创建进程就设定了。
  7. 多级反馈队列调度 (Multilevel Feedback Queue Scheduling):
    • 抢占式的调度算法
    • 将进程分配到多个队列中,根据规则选择队列进行调度。
    • 适用于多种类型的进程,但需要合理设置队列的优先级和时间片大小,可能存在优先级反转问题。
    • 多级反馈队列调度算法是对其他算法的⼀个折中权衡。是「时间⽚轮 转算法」和「最⾼优先级算法」的综合和发展。

8. 什么情况下会产生死锁?怎么解决?

死锁是指在多个进程(或线程)之间,每个进程都占有某些资源,同时又等待其他进程释放它所需要的资源,从而导致所有进程都无法继续执行下去的⼀种状态。

死锁产生的原因通常有以下几种情况:

  1. 竞争资源:不同的进程同时竞争同⼀个资源,但是每个进程又需要其他进程占有的资源才能继续执行。
  2. 不恰当的资源分配顺序:如果资源分配的顺序不当,可能会导致某个进程⼀直等待其他进程占有的资源。
  3. 循环依赖:多个进程之间形成了循环依赖,每个进程都在等待其他进程释放资源。

我们来分析一下死锁产生的必要条件。如果你想避免死锁,只要破坏这四个条件中的一个或者几个,就可以了。

  1. 互斥: 至少一个资源是被排他性独享的,其他线程必须处于等待状态,直到资源被释放。
  2. 持有和等待:进程已经持有了至少一个资源,并且在等待获取其他进程占有的资源。
  3. 不可剥夺:已经分配给进程的资源不能被强制性地抢占,只能由持有该资源的进程主动释放。
  4. 环路等待:存在一个进程资源的循环等待链,每个进程都在等待下一个进程所持有的资源。

解决死锁的方法:

  1. 死锁预防:通过破坏死锁产生的必要条件来预防死锁,例如破坏互斥条件、破坏请求与保持条件、破坏不可剥夺条件或破坏循环等待条件。
  2. 死锁避免:通过动态地分配资源,避免系统进入可能导致死锁的状态。采用安全序列算法来判断分配资源是否会导致死锁,并避免产生不安全序列。
  3. 死锁检测:可以通过资源分配图等⽅式检测死锁是否已经发生。
  4. 死锁解除:当发现死锁已经发⽣时,可以采取⼀些措施解除死锁,比如中断某个进程、回收某个进程占用的资源等

9. I/O多路复用

通过单个线程同时监听多个IO事件的机制,以提高系统的IO效率。

它基于操作系统提供的一些特定的系统调用,如selectpollepoll(在Linux中)、kqueue(在BSD和macOS中)等。

多路复用的原理是将多个IO事件注册到一个统一的事件管理器中,并通过阻塞等待的方式,一旦有任何一个IO事件就绪(即可读、可写或出现异常),操作系统会通知应⽤程序, 应⽤程序可以通过遍历事件集合找出就绪的事件,并进⾏相应的处理。这样就可以通过一个线程同时处理多个IO事件,而不需要为每个事件创建独立的线程。

I/O多路复用的优点包括:

  1. 节省系统资源:使用单个线程处理多个IO事件,避免了为每个事件创建线程的开销,节省了系统资源。
  2. 提高系统吞吐量:通过并发处理多个IO事件,提高了系统的吞吐量和响应性能。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞