操作系统篇----进程管理 参考王道操作系统与小林coding的图解操作系统整理的md文档

前置:简单的个人学习笔记上传,仅供参考,想要md文档的可以评论留言

参考内容

CSDN博主 BitHachi的博文 《王道操作系统》学习笔记总目录+思维导图

CSDN博主 小林coding的图解操作系统

2 进程管理

2.1 进程与线程

2.1.1 进程的定义、特征、组成、组织
  • 进程的定义

    • 程序段、数据段 、PCB(进程控制块)三部分组成了进程实体。一般情况下我们把进程实体简称为进程。

    所谓的创建进程和撤销进程,一般都指的是创建或者撤销进程实体中的PCB。

    进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位

  • 进程和程序的区别

    • 组成不同:进程包含程序段、数据段、PCB。程序包含数据和指令代码。
    • 程序本身除了占用磁盘的存储空间外,并不占用系统的CPU、内存等运行资源。但是进程会占用系统的CPU、内存等运行资源。
    • 进程更强调动态性,而程序一般则是静态的。
    • 进程不能脱离具体的程序而虚设,程序规定了相应的进程要完成的动作。
  • 进程的特征

    • 动态性(最基本的特征):进程是程序的一次执行过程,是动态地产生、变化和消亡的
    • 并发性:内存中可以有多个进程实体,各进程可以并发执行
    • 独立性:进程是能独立运行、独立获得资源、独立接受调度的基本单位
    • 异步性:各进程独立运行,需要操作系统提供”进程同步机制”来解决异步问题
    • 结构性:每个进程都有一个PCB(进程控制块),进程由程序段,数据段,PCB组成
  • 进程的组成

    • 程序段
    • 数据段
    • PCB(Process Control Block)
      • PCB是进程存在的唯一标识
      • OS是根据PCB来对并发执行的进程进行控制和管理的

    img

  • 进程的组织

    • 链接方式
      • 按照进程状态将PCB分为多个队列
      • 操作系统持有指向各个队列的指针
    • 索引方式
      • 根据进程状态的不同,建立几张索引表
      • 操作系统持有指向各个索引表的指针

    进程的状态有 就绪态 执行态 阻塞态

    单核CPU计算机中同一时刻只会有一个进程处于运行态

    通常会把优先级高的进程放到队头

2.1.2 进程的状态及转换
  • 三种基本状态

    • 运行态:占有CPU,并在CPU上运行
    • 就绪态:具备运行条件(除CPU以外的资源),没有空闲CPU
    • 阻塞态:等待某一时间而暂时不能运行
  • 另外两种状态

    • 创建态:OS正在为进程分配资源,初始化PCB
    • 终止态:正在回收相应的资源,撤销PCB
  • 状态的转换

    image-20220420130952104

    • 创建态------>就绪态
      • 系统创建进程获得除CPU以外的其他资源
    • 就绪态------>运行态
      • 进程被调度,获取CPU时间片
    • 运行态------>就绪态
      • 时间片用完或处理机被其他进程抢占
    • 运行态------>阻塞态
      • 进程通过“系统”调用申请某个资源或者请求等待某个事件,是一种主动行为
    • 阻塞态------>就绪态
      • 申请的资源得到,等待的时间发生,是一种被动的行为
    • 运行态------>终止态
      • 进程正常结束,或者运行中遇到不可修复的错误

    注:不能由阻塞态直接转换为运行态,也不能直接由就绪态直接转换为阻塞态

    因为进程进入阻塞态是主动行为,只有在运行时才可以主动发出请求

2.1.3 原语实现对进程的控制
  • 进程控制:实现进程在不同状态间的转换
  • 原语实现对进程的控制
    • 通过开中断指令和关中断指令实现
    • 原语的操作具有原子性,只能一气呵成
    • 原语的操作
      • 更新PCB中的信息
      • 将PCB插入合适的队列
      • 分配/回收资源
  • 进程控制的五种原语
    • 创建原语
      • 为新进程分配一个唯一的进程标识号,申请空白PCB,PCB是有限的,申请失败则创建失败
      • 分配资源
      • 初始化PCB
      • 将PCB插入相应的队列
    • 终止原语
      • 从PCB集合中找到要终止的PCB
      • 若进程正在运行,立刻剥夺CPU,分配给其他进程
      • 终止所有子线程
      • 将资源归还给其父线程或者OS
      • 删除PCB
    • 唤醒和阻塞原语(成对存在,成对使用)
      • 阻塞原语
        • 找到PCB
        • 保护进程运行现场,将PCB状态信息设为“阻塞态”,暂时停止进程运行
        • 将PCB插入相应的队列
      • 唤醒原语
        • 在阻塞队列中找到PCB
        • 将PCB从等待队列中移除,设置进程为就绪态
        • 将PCB插入就绪队列,等待调度
    • 切换原语
      • 将运行环境信息存入PCB
      • PCB移入相应的队列
      • 选择另一个进程执行,并更新其PCB
      • 根据PCB恢复新进程所需的运行环境
2.1.4 进程通信
  • 共享存储:设置一块共享空间,两个进程互斥地访问共享空间

    • 基于数据结构的共享:速度慢,限制多,是一种低级通信方式
    • 基于存储区的共享:内存中有一块共享存储区,数据的存放及数据的结构有进程控制,是一种高级通信方式
  • 管道通信:在内核内存中开辟一个大小固定的缓冲区,通信数据遵循先进先出

    • 特征:

      • 管道只能采用半双工通信,即某段时间内只能实现单项的传输,要实现双向同时通信,要设置两个管道。
      • 各进程互斥的访问管道
      • 数据以流的形式写入管道
      • 没有写满不允许读,没读空不允许写
      • 数据被读出就会从管道中抛弃,因此只能有一个读进程
    • 分类

      • 匿名管道

        • 匿名管道会生成两个描述符,一个是管道的读取端描述符,一个是管道的写入端描述符
        • 父进程通过fork创建子进程,创建的子进程会复制父进程的文件描述符。
        • 只能实现存在父子关系的进程之间的通信
      • 命名管道

        • 提前创建类一个类型为管道的设备文件
        • 可以在不相关的进程间进行通信
  • 消息队列:存放在内核中的消息链表

    • 进程间的数据交换以格式化的消息为单位,进程通过OS提供的“发送消息/接受消息”两个原语进行数据交换
    • 发送信息的进程将消息头写好,接受信息的进程根据消息头读取信息或寻找信封是哪一个
    • 不适合叫大数据的传输
    • 通信过程中会存在用户态和内核态之间的数据拷贝开销
  • 信号量:用于实现进程间的互斥和同步,需要借助共享内存来实现进程间的通信

    • 整型信号量

      • 表示某种资源的数量

      • 对信号量的操作只有初始化,P(wait),V(signal)

        • void wait (int s){//wait原语,属于原子操作,不可中断,相当于进入区,检查并上锁
          	while(s<=0);// 一直检查是否有空闲资源
              s=s-1;//有资源,就占用资源
          }
          
          void  signal(int s){//signal原语,相当于退出区
          	s=s+1;//归还使用的资源
          }
          
  • 信号

    • 通过给进程发送信号实现与某个进程进行交互

    • 通过kill -l 命令可以查看信号

      root@mathroot:/home/mathroot/test# kill -l
       1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
       6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
      11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
      16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
      21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
      26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
      31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
      38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
      43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
      48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
      53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
      58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
      63) SIGRTMAX-1	64) SIGRTMAX	
      
    • 信号举例

      • Ctrl + C 产生 SIGINT信号,终止进程
      • Ctrl + Z 产生 SIGTSTP 信号,停止进程但是并未终止
      • kill -9 pid 给pid发送 SIGKILL 信号,用来结束进程
    • 信号应答机制

      • 执行默认操作
      • 捕捉信号,执行信号对应的信号处理函数
      • 忽略信号
  • Socket:实现不同主机之间的进程之间的通信

    • socket的系统调用

      int socket(int domain,int type,int protocal)
      
      • domain用于指定协议族
        • AF_INET------->IPV4
        • AF_INET6------>IPV6
        • AF_LOCAL/AF_UNIX------->localhost
      • type用于指定通信特性
        • SOCK_STREAM表示字节流,对应TCP
        • SOCK_DGRAM表述数据报,对应UDP
        • SOCK_RAW表示原始套接字
      • protocal指定通信协议,基本废弃,写0即可
    • 基于TCP协议通信的socket编程

      image-20220420160856101

      • 服务端和客户端初始化 socket,得到文件描述符;

      • 服务端调用 bind,将绑定在IP地址和端口;

      • 服务端调用 listen,进行监听;

      • 服务端调用 accept,等待客户端连接;

      • 客户端调用 connect,向服务器端的地址和端口发起连接请求;

      • 服务端 accept 返回用于传输的 socket 的文件描述符;

      • 客户端调用 write 写入数据;服务端调用 read 读取数据;

      • 客户端断开连接时,会调用 close,那么服务端 read 读取数据的时候,就会读取到了EOF,待处理完数据后,服务端调用 close,表示连接关闭。

        用于监听的socket和用来传送数据的socket是两个socket,一个叫做监听socket,一个叫做已完成连接socket

    • 基于UDP协议通信的socket编程

      image-20220420161339475

    • 基于本地进程间通信的socket编程

2.1.5 线程概念与多线程模型
  • 线程的定义:线程是“轻量级的进程”,是一个基本的CPU执行单元,也是程序执行流的最小单位。

  • 进程与线程

    • 进程是资源分配的基本单位,线程是调度的基本单位
  • 线程的实现方式

    • 用户级线程(User-Lever Thread)
      • 用户可以看到的线程
      • 用户级线程由应用程序通过线程库实现,线程切换在用户态即可完成。
    • 内核级线程(Kernel-Level Thread)
      • 操作系统内核可以看到的线程
      • 内核级线程的管理由操作系统内核完成,内核级线程的切换需要在核心态下完成。
      • 只有内核级线程才是处理机分配的单位
    • 轻量级进程(LightWeight Process)
      • 内核线程的一种高级接口,用来支持用户线程
  • 多线程模型

    • 多对一模型:多个用户线程映射到一个内核级线程

      • ULT的切换在用户态即可完成,线程管理的系统开销小,效率高
      • 一个ULT阻塞时,整个进程都会被阻塞,并发度不高,多个线程不能在多喝处理及上并行运行
    • 一对一模型:一个ULT映射到一个KLT上

      • 一个线程被阻塞后,别的线程还可以继续执行,并发性强。多线程可以在多核处理机上并行执行
      • 一个用户进程会占用多个内核级线程,线程切换由OS内核完成,需要切换到核心态,线程管理的成本高,开销大。
    • 多对多模型:n个用户级线程映射到M个内核级线程上

      • 克服了并发度不高,以及进程占用太多内核级线程,开销太大的缺点

2.2 处理机的调度机制

2.2.1 处理机调度的基本概念和调度的三个层次
  • 调度的基本概念
    • 处理机调度就是从就绪队列中按照一定的算法选择一个进程并将处理机分配给它运行,以实现进程的并发执行。
  • 调度的三个层次
    • 高级调度(作业调度)
      • 从后备队列中选择合适的作业将其调入内存,并为其创建进程
      • 发生频率最低
      • 外存--------->内存 面向作业
    • 中级调度(内存调度)
      • 从挂起队列中选择合适的进程将其数据调回内存
      • 发生频率中等
      • 外存------>内存 面向进程
    • 低级调度(进程调度)
      • 从就绪队列中选择一个进程为其分配处理机
      • 发生频率最高
      • 内存----->CPU
2.2.2 进程调度的时机,方式以及切换过程
  • 进程调度的时机

    • 需要调度

      • 当前进程主动放弃处理机
      • 当前进程被动放弃处理机
    • 不能调度与切换的情况

      • 处理中断的过程
      • 进程在操作系统内核程序临界区中
      • 在原子操作过程中(原语)

      临界区:访问临界资源的那段代码

      临界资源:一段时间内只允许一个进程使用的资源,各进程需要互斥地访问临界资源

      • 内核程序临界区
      • 普通临界区 :可以进行进程的调度与切换
  • 进程调度的方式

    • 抢占式调度
    • 非抢占式调度
      • 选中的进程会一直运行,直到进程退出或者进程阻塞
  • 进程的切换

    • 狭义的进程调度:从就绪队列中选一个要运行的程序
    • 进程切换:一个进程让出虚拟机,另一个进程占用处理机
    • 广义的进程调度:选择一个进程以及进程切换

    注:进程切换时有代价的,如果过于频繁的进行进程调度和切换回事整个系统的效率降低。

2.2.3 进程调度算法的评价指标
  • CPU利用率

    • 如果运行的程序,发生了/O事件的请求,那CPU使用率必然会很低,因为此时进程在阻塞等待硬盘的数据返回。这样的过程,势必会造成CPU突然的空闲。所以,为了提高CPU利用率,在这种发送/O事件致使CPU空闲的情况下,调度程序需要从就绪队列中选择一个进程来运行。
  • 系统吞吐量

    • 有的程序执行某个任务花费的时间会比较长,如果这个程序一直占用着CPU,会造成系统吞吐量(CPU在单位时间内完成的进程数量)的降低。所以,要提高系统的吞吐率,调度程序要权衡长任务和短任务进程的运行完成数量。
  • 周转时间

    • 从进程开始到结束的过程中,实际上是包含两个时间,分别是进程运行时间和进程等待时间,这两个时间总和就称为周转时间。进程的周转时间越小越好,如果进程的等待时间很长而运行时间很短,那周转时间就很长,这不是我们所期望的,调度程序应该避免这种情况发生。
  • 等待时间

    • 处于就绪队列的进程,也不能等太久,当然希望这个等待的时间越短越好,这样可以使得进程更快的在CPU中执行。所以,就绪队列中进程的等待时间也是调度程序所需要考虑的原则。
  • 响应时间

    • 对于鼠标、键盘这种交互式比较强的应用,我们当然希望它的响应时间越快越好,否则就会影响用户体验了。所以,对于交互式比较强的应用,响应时间也是调度程序需要考虑的原则。
2.2.4 调度算法
  • 先来先服务(First Come First Severed,FCFS)

    • 每次从就绪队列选择最先进⼊队列的进程,然后⼀直运⾏,直到进程退出或被阻塞,才会继续从队列中选择第⼀个进程接着运⾏。
  • 短作业优先(Shortest Job First,SJF)

    • 优先选择运行时间短的进程,对短作业有利
  • 高响应比优先(Highest Response Ratio Next, HRRN)

    • 响 应 优 先 级 = 等 待 时 间 + 要 求 服 务 时 间 要 求 服 务 时 间 响应优先级= \frac{等待时间+要求服务时间}{要求服务时间} =+

    • 当两个进程的等待时间相同时,服务时间越短,响应优先级越高

    • 如果两个进程的要求服务时间相同时,等待时间月导航响应优先级越高

  • 时间片轮转调度算法(Round Robin,RR)

    • 抢占式算法,就绪队列中的进程轮流执行一个时间片
  • 最高优先级调度算法(Highest Priority First,HPF)

    • 进程的优先级分类

      • 静态优先级

        • 创建进程时就确定了优先级
      • 动态优先级

        • 根据进程的动态变化改变优先级,等待时间变长优先级增加,执行时间变长优先级降低
    • 算法分类

      • 抢占式:出现比当前运行线程优先级高的进程就将当前进程挂起,调度优先级高的进程
      • 非抢占式:运行玩当前线程再选择优先级高的进程
  • 多级反馈队列调度算法(Multilevel Feedback Queue)

    • 设置了多个队列,赋予每个队列不同的优先级,每个队列优先级从高到低,同时优先级越高时间片越短
    • 新的进程会被放入到第一级队列的末尾,按先来先服务的原则排队等待被调度,如果在第一级队列规定的时间片没运行完成,则将其转入到第二级队列的末尾,以此类推,直至完成
    • 当较高优先级的队列为空,才调度较低优先级的队列中的进程运行。如果进程运行时,有新进程进入较高优先级的队列,则停止当前运行的进程并将其移入到原队列末尾,接着让较高优先级的进程运行;

2.3 进程的同步与互斥

2.3.1同步与互斥
  • 进程同步

    • 进程同步也称为直接制约关系

    • 进程同步是为了解决进程异步的问题

      异步性:各并发执行的线程以各自独立的、不可预知的速度向前推进

  • 进程互斥

    • 互斥又称间接制约关系,是指当一个进程访问某个临界资源时,另一个想要访问该临界资源的进程必须等待。

      临界资源:一个时间段内只允许一个进程使用的资源称为临界资源,许多物理设备(摄像头,打印机)都属于临界资源。此外,一些变量,数据,内存缓冲区等都属于临界资源。

    • 对临界资源的互斥访问

      • 进入区:判断能否进入(即能否获得锁)
      • 临界区:进程中访问临界资源的代码
      • 退出区:释放锁
      • 剩余区:其它动作
    • 对临界资源进行互斥访问的准则

      • 空闲让进
      • 忙则等待
      • 有限等待
      • 让权等待
2.3.2 临界区进程互斥的实现方法
  1. 软件实现方法
    • 单标志法:一个进程访问完临界区后,将访问权限转交给另一个进程。
      • 可以实现互斥
      • 违背“空闲让进”原则
    • 双标志先检查法:检查有没有别的进程想进入临界区
      • 违反“忙则等待”的原则,检查和上锁不是原子性操作
    • 双标志后检查法:先上锁,再检查有没有其他线程想要进入临界区
      • 违背“空闲让进”以及“有限等待”,上锁和检查不是原子性操作
    • peterson算法:主动谦让,检查对方是否想进入,自己是否谦让。
  2. 硬件实现方法
    • 中断屏蔽法
      • 关中断和开中断指令实现
      • 简单高效但是不适用于多处理机,只适用于操作系统的内核进程
    • TestAndSet(ts或tsl指令)
      • 无论之前是否加锁都将锁设置为true,然后返回设置之前的值
      • 违背让权等待,导致忙等
    • Swap指令
      • 与ts指令类似
2.3.3 信号量机制
  • 信号量机制:信号量其实就是一个变量,可以是整数也可以是复杂的记录型变量,可以用信号量来表示系统中某种资源的数量。通过wait以及signal原语对信号量进行操作,可以方便的实现进程互斥,进程同步。

  • 整型信号量

    • 表示某种资源的数量

    • 对信号量的操作只有初始化,P(wait),V(signal)

      • void wait (int s){//wait原语,属于原子操作,不可中断,相当于进入区,检查并上锁
        	while(s<=0);// 一直检查是否有空闲资源
            s=s-1;//有资源,就占用资源
        }
        
        void  signal(int s){//signal原语,相当于退出区
        	s=s+1;//归还使用的资源
        }
        
  • 记录型信号量

    • 一个变量value维护资源数量,一个维护等待该资源的阻塞队列L。

    • 对信号量的操作

      • void wait(Semphore s){
            s.value--;
            if(s.value<0){
        		block(s.L);//剩余资源数不够,利用block原语使当前进程进入阻塞态,并加入当前资源的阻塞队列中
            }
        }
        
        void signal(Semphore s){
            s.value++;
            if(s.value<=0){
        		wakeup(s.L);//释放资源后,还有其它进程在等待资源,使用wakeuo原语唤醒该资源的等待队列中的一个进程,将其从阻塞态变为就绪态
            }
        }
        
2.3.4 信号量机制实现进程的同步,互斥和前驱关系
  • 实现进程互斥

    • 划定临界区
    • 设置对应的信号量 s.value=1
    • 在临界区前执行P(s)
    • 在临界区后执行V(s)
  • 实现进程同步

    • 找到需要进行同步的两个操作

    • 设置同步信号量,将资源数初始化为0,即s.value = 0;

    • 在前操作之后执行 V(s)

    • 在后操作之前执行P(s)

    • s.value = 0;
      
      void m1(){
      	//code1...;
          //code2...;
          //precode...;
          //signal(s);
          //othercodes...;
      }
      
      void m2(){
      	//code1...;
          //code2...;
          //wait(s);
          //postcode...;
          //othercodes...;
      }
      
  • 实现前驱关系

    • 将每一对前驱关系看作是同步关系即可。
2.3.5 进程同步与互斥的经典问题
  1. 生产者-消费者问题
    semphore1.mutex = 1;  //生产者与消费者线程互斥
    semphore2.empty = n;  //生产同步  没满可以生产
    semphore3.full = 0;   //消费同步  非空可以消费
    
    void producer(){
        while(true){
            produece();//生产一个产品
            wait(empty);//消耗一个空闲缓冲区
            wait(mutex);//互斥锁定
            put(product);//把产品放入缓冲区
            signal(mutex);//互斥唤醒
            signal(full);//增加一个产品
        }
    }
    
    void consumer(){
    	while(true){
            wait(full);//消耗一个非空缓冲区
            wait(mutex);//互斥锁定
            take(product);//拿走产品
            signal(mutex);//互斥唤醒
            signal(empty);//增加空闲缓冲区
        }
    }
    

    实现互斥的wait操作一定要在实现同步的wait操作之后,否则有可能造成死锁现象

  2. 多生产者-多消费者问题
  3. 读者-写者问题
    semphore rCountMuTex = 1;//读者个数临界区的互斥锁
    semphore wDataMutex = 1;//写者的互斥锁
    semaphore flag = 1;//公平竞争
    int rCount = 0;//读者个数
    
    void writer(){
        while(TRUE)
        {
            P(flag);//写机会
            P(wDataMutex); //写写互斥
            write();
            V(wDataMutex);
            V(flag);
        }
    }
    
    void reader(){
        while(TRUE){
            
            P(flag);//读机会
            P(rCountMutex);
            if(rCount == 0){
                P(wDataMutex);//读写互斥
            }
            rCount++;
            V(rCountMutex);
            V(flag);
            
            read();
            
            P(rCountMutex);
            rCount--;
            if(rCount == 0){
                V(wDataMutex);//读写互斥
            }
            V(rCountMutex);
        }
    }
    
  4. 吸烟者问题
  5. 哲学家进餐问题
    #define N 5 //哲学家个数
    semaphore fork[5]; / /每个叉子一个信号量,初值为1
    void smart_person(int i) // i 为哲学家编号 0-4
    {
        while( TRUE)
        {
            think( ); // 哲学家思考
    		if (i%2==0)
            {
                P(fork[i]); //去拿左边的叉子
    			P(forkl(i+1)  N 1);// 去拿右边的叉子
            }
            else
            {
                P(forkl(i + 1) % N ]);// 去拿右边的叉子
    			P(fork[i]); //去拿左边的叉子
            }
    		eat(); // 哲学家进餐
            
    		V(fork[i]); //放下左边的叉子
    		V(fork[(i + 1) % N J); //放下右边的叉子
    	}
    }
    
2.3.6 管程与java中管程的实现机制
  • 管程是一种并发控制机制,由编程语言来具体实现,负责管理共享资源以及对共享资源的操作,并提供多线程环境下的互斥和同步,以支持安全的并发访问。

  • 管程出现原因:

    • 信号量和互斥量都是低级原语,使用它们需要手动编写wait和signal逻辑,容易产生死锁。
    • 管程可以对开发者屏蔽掉这些细节,在语言内部实现,更加简单易用
  • 管程的组成

    • 临界区
    • 条件变量,用来维护不满足条件而阻塞的线程
    • monitor对象,维护管程的入口,临界区互斥量(锁),临界区和条件变量,以及条件变量上的阻塞和唤醒。
2.3.7 死锁
  • 死锁发生的四个必要条件
    • 互斥条件
    • 不可剥夺条件
    • 持有并等待条件(请求并保持条件)
    • 循环等待条件
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 27
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值