操作系统复习版一

一:进程

1.进程状态转换
  进程包括新建、就绪、阻塞、运行以及退出状态。
  当有一个请求需求时,进程可能会被创建。当一个处于运行状态的进程需要等待某个事件或者资源的发生时,它就从运行态转换到阻塞态,当事件或者资源到达,那么就会转为就绪态,当操作系统调度该就绪进程,为其分配时间片的时候,该进程就从就绪态转为运行态。当运行态的进程时间片用尽或者被其他更高优先级的进程抢占,那么该进程就从运行态转为就绪态。此外,当内存不够时,或者为了提高系统性能,常常会将处于阻塞态的位于内存中的进程的一部分信息从内存移到磁盘上,以腾出更多的内存空间。此时被从内存调入磁盘的进程就处于挂起状态。
2.进程创建
  (1)给新进程分配一个唯一的进程标识符。在主进程表中增加一项,其中每一项都表示一个进程的指针。
  (2)给进程分配空间:也就是分配进程映像中的所有元素,包括程序、数据、栈和属性。给进程控制块分配空间。
  (3)初始化进程控制块。
  (4)设置正确的连接:比如将进程放置到某个就绪或者挂起链表中。
  (5)创建和扩展其他数据结构:比如操作系统可能为每个进程保存一个记账文件,可用于编制账单或者用于进行性能评估。
3.进程切换
  (1)何时切换:在操作系统发生中断、陷阱或者系统调用的时候会发生进程的状态切换。最常见的就是系统中断,系统中断分为中断和陷阱。中断就是指与本进程无关,是由于外部事件的触发导致中断产生,从而引起本进程状态切换。常见的普通中断有时钟中断(时间片失效),IO中断(操作系统发生了IO活动),内存失效(处理器访问了一个虚拟内存地址,但这个地址不在内存中,必须进行段或者页的调入工作)。陷阱就是指本进程在执行的过程中发生了错误或者异常,当错误或者异常致命,那么就从运行态转换为退出态。系统调用是说在进程执行系统调用,这个调用会导致转移到作为操作系统代码一部分的一个例程上执行。通常,使用系统调用会导致把用户进程置为阻塞态。
  (2)进程切换的步骤:

1.保存处理器上下文环境,包括程序计数器和其他寄存器。
2.更新当前处于运行态进程的进程控制块,包括将进程的状态改变到另一状态。还必须更新其他相关域,包括离开运行态的原因和记账信息。
3.将进程的进程控制块移到相应的队列。
4.选择另一个进程执行。
5.更新所选择进程的进程控制块,包括将进程的状态改为运行态。
6.更新内存管理的数据结构,这取决于如何管理地址转换。
7.恢复处理器在被选择的进程最近一次切换出运行状态时的上下文环境,这可以通过载入程序计数器和其他寄存器以前的值来实现。

二:线程

1.线程同步
  一个进程中的所有线程共享同一个地址空间和诸如打开的文件之类的其他资源,一个线程对资源的任何修改都会影响同一个进程中其他线程的环境,因此,需要同步各种线程的活动,以便它们互不干涉且不破坏数据结构。
2.用户级线程和内核级线程
  用户级线程:有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在,任何应用程序都可以通过使用线程库被设计成多线程程序,线程库用于用户级线程管理的例程包,包含创建和销毁线程的代码、在线程之间传递消息和数据的代码、调度线程执行的代码、以及保存和恢复线程上下文的代码。
  内核级线程:有关线程管理的所有工作都由内核完成,应用程序部分没有进行线程管理的代码,只有一个到内核线程设施的应用程序编程接口。内核为进程及其内部的每个线程维护上下文信息。调度是由内核基于线程完成的。如果内核中的一个线程被阻塞,内核可以调度同一进程中的另一个线程。并且可以把同一个进程中的多个线程调度到多个处理器中。但是在把控制从一个线程传送到同一进程中的另一个线程时,需要内核的状态切换
3.线程阻塞
 3.1 用户级
  当用户级线程执行一个系统调用时,不仅这个线程会被阻塞,进程中的所有线程都会被阻塞。其次,在纯粹的用户级线程策略中,一个多线程应用程序不能利用多处理技术。内核一次只能把一个进程分配给一个处理器,因此一次进程中只有一个线程可以执行,事实上,在一个进程中,我们相当于实现了应用程序级别的多道程序。尽管多道程序会使得应用程序的速度明显提高,但是同时执行部分代码更会使得某些应用程序受益。
  当然,我们可以采用把应用程序写成一个多进程程序而非多线程程序来解决这两个问题。但进程之间切换消耗开销比较大。除此之外,还有一个解决方法称为jacketing技术。它的目标是把一个产生阻塞的系统调用转化成一个非阻塞的系统调用。例如,不是直接调用一个系统IO例程,而是让线程调用一个应用级的IO jacking例程,该例程就是用来检测并确定IO设备是否在忙,如果忙,该线程进入阻塞态并将控制权传送给另外一个线程,当这个线程后来重新获得控制时,jacket例程会再次检查IO设备。
 3.2 混合方法
  混合采用用户级线程和内核级线程的方式,线程创建、调度和同步在应用程序中,只有多个用户级线程被映射到一些内核级线程上,以便开发人员调整,以达到最佳效果。同一个应用程序中的多个线程可以在多个处理器上并行运行,某个会引起阻塞的系统调用不会阻塞整个进程

三:并发性:互斥和同步

3.1互斥
  当一个进程被赋予互斥的能力时,它具有排斥所有其他进程的能力。互斥的方案有:信号量、管程(条件变量)和消息传递
  在并发中有一些概念:

1.原子操作:一个函数或者动作由一个或多个指令的序列实现,对外是不可见的。原子操作保证了并发进程的隔离。
2.临界区:是一段代码,在这段代码中进程将要访问共享资源,当另外一个进程已经在这段代码中运行时,这个进程就不能在这段代码中执行。
3.死锁:两个或者两个以上的进程因其中的每个进程都在等待其他进程做完某些事情而不能继续执行,这种情形称为死锁。也就是互相等待
4.活锁:两个或两个以上进程为了响应其他进程中的变化而持续改变自己的状态但不做一些有用的工作,这种情形称为活锁。
5.互斥:当一个进程在临界区访问某些共享资源时,其他进程不能进入该临界区访问任何共享资源,这种情形称为互斥。
6.竞争条件:多个线程或者进程在读写一个共享数据时,结果依赖于他们执行的相对时间,这种情形称为互斥。
7.饥饿:是指一个可运行的进程尽管继续执行,但被调度程序无限期地忽视,而不能调度执行的情形。也就是无限等待。

忙等待或自旋等待:就是说进程在得到临界区访问权之前,它只能继续执行测试变量的指令来得到访问权,除此之外不能做其他事情。(就是说一直测试询问是否可以得到访问权,而不做其他事情)。
3.2 信号量
 1.常见并发机制

1.信号量:它是一个用于进程间传递信号的一个整数,在信号量上只有三种操作可以进行:初始化、递减和增加,这三种操作都是原子操作。递减操作可以用于阻塞一个进程,增加操作可以用于解除阻塞的一个进程,也称为计数信号量或一般信号量。
2.二元信号量:只取0和1的信号量。
3.互斥量:类似于二元信号量,区别在于为其加锁(设为0)或者为其解锁(设为1)的进程必须为同一进程。
4.条件变量:一种数据类型,用于阻塞进程或线程,直到特定的条件为真。
5.管程:一种编程语言结构,在一个抽象数据类型中封装了变量、访问过程和初始化代码。管程的变量只能由管程自己的访问过程来访问,每次只能有一个进程在其中执行。访问过程即临界区。管程可以有一个等待进程队列。
6.事件标志:作为同步机制中的一个内存字。应用程序代码可以为标志中的每一位关联不同的事件。通过测试相关的一个或多个位,线程可以等待一个事件或多个事件。在全部的所需位都被设定(and)或至少一个位被设定(or)之前,线程会一直被阻塞。
7.信箱/消息:两个进程交换信息的一种方法,也可以用于同步。
8.自旋锁:一种互斥机制,进程在一个无条件循环中执行,等待锁变量的值变为可用。

2.信号量基础
  信号量: 代表一种计数,semWait操作使得信号量减1,代表执行该原语的进程被阻塞,相反,当执行semSignal操作的时候,使得信号量增1,代表执行该原语的进程被释放。也正是因为如此,在二元信号量中,可能由某个进程对某个信号量进行了加锁操作,而由另一个进程为其进行解锁操作。
  而对与二元信号量相对的互斥量来说,加锁和解锁必须是同一个进程
  但无论是计数信号量还是二元信号量,都需要使用队列来保存在信号量上等待的进程。因此就有了先进先出的公平策略,而采用这个策略的信号量是强信号量不按顺序的信号量称为弱信号量
  关于信号量:就是当信号量s的值大于等于0时,表示的是可以执行semWait(s)而不被阻塞的进程数,也可以理解成有多少份资源可以使用,这种情形允许信号量支持同步与互斥。但是当信号量的值小于0时,它的值的大小代表的是阻塞在队列中的进程数
 3.生产者消费者问题
  该问题中,由于当缓冲区满时,生产者线程进程必须要阻塞,等待消费者进程将数据移出缓冲区,而当缓冲区空时,消费者需要等待直到生产者线程成功将数据生产至缓冲区。
 4.哲学家进餐问题
3.3 管程
 1.管程基本概念
  管程是由一个或者多个过程、一个初始化序列和局部数据组成的软件模块,主要特点如下:

(1)局部数据变量只能被管程的过程访问,任何外部过程都不能访问。
(2)一个进程通过调用管程的一个过程进入管程。
(3)在任何时候,只能有一个进程在管程中进行,调用管程的任何其他进程都被阻塞,以等待管程可用。

管程通过使用条件变量提供对同步的支持,这些条件变量包含在管程中,并且只有在管程中才能被访问。
  条件变量与信号量似乎相似,但是却明显不同,首先,与信号量具有值的概念不同,条件变量没有关联的值;其次,在管程中执行signal操作时,如果相应的阻塞队列中没有阻塞进程,则本次操作为空操作,即什么也不做;而在信号量中则不会出现这种情况,V操作在阻塞队列中没有阻塞进程时也必须对信号量进行加1操作(资源个数增1)。
3.4 进程通信
 1.进程通信的方式分为低级通信和高级通信。低级通信进程之间一次只能传递很少的信息,之前提到的信号量其实就是一种低级通信的方式。而高级通信又可以细分为共享内存通信方式,共享文件通信方式(管道)以及消息传递通信方式。消息传递通信可细分为消息缓冲通信方式(直接通信方式)和信箱通信方式(间接通信方式)。
 2.共享内存通信方式
  实际上,需要通信的双方进程将自己的虚拟地址空间映射到共享内存分区上,通信时,发送进程将数据写入该共享内存中,而接收方在共享内存中读取数据,这样就达到了通信的目的。在进程需要利用共享内存进行通信的时候,必须先通过系统调用去创建申请使用共享内存的一块分区,若已建立,就返回这个分区的描述符,如果没有,那么为该进程建立指定大小的共享内存分区。之后还必须通过系统调用附接将共享内存分区连接到自己的虚拟地址空间上,并指定该内存分区的访问属性,即指明该分区是只读还是可读可写。此后,这个共享内存分区就成为该进程虚拟地址空间的一部分。当进程不再需要该共享内存分区时,再通过系统调用断接把该共享内存分区与进程断开。
 3.消息传递基本概念
  消息传递实际上以一对原语的形式提供:send(dest,msg),receive(source,msg),这是进程间进行消息传递的最小操作集,一个进程以消息的形式给另一个指定的目标进程发送消息,进程通过执行receive原语接受信息,receive原语中指明发送消息的源进程和消息。
  同步:两个进程之间消息传递隐含着某种同步信息,只有当一个进程发出消息之后,接收者才能接收消息,此外,当一个进程发出了send和receive原语之后,我们需要确定会发生什么。
  (1)消息缓冲通信方式
   单向通信:发送方在发送完消息之后,不等消息被接收者接收就继续前进,而接收者接收到消息之后也不给发送者发送回答信息。
   双向通信:发送者发送完消息之后阻塞自己直到收到接收者的回答信息之后才继续前进,接收者在未收到消息之前也阻塞自己直到接收到发送者发送来的消息,并给发送者发送一个回答信息。
   通信过程如下:
   1)发送者先将要发送的信息保存在自己的内存空间中的设置的一个发送区中;
   2)发送者申请一个消息缓冲区,将已经准备好的消息从发送区送到消息缓冲区,并将发送者进程的名字,消息开始地址以及长度等信息填入消息缓冲区中,然后把消息缓冲区挂到接收进程的消息链上。
   3)接收者在接收消息之前先在自己的内存空间设置一个相应的接收区;
   4)接收者从消息链上摘下第一个消息,将该消息从消息缓冲区复制到接收区,然后释放该消息缓冲区;
   当然,消息链是临界资源,也就是说对消息队列的操作是临界区,保证发送和接收操作的互斥性,由于可能同时存在多个发送者申请消息缓冲区,也就是说消息缓冲区也是临界资源。因此可以将步骤2封装成为发送原语send,将第4步封装成为接收原语receive。
 (2)信箱通信方式
  进程之间的通信要借助称为信箱的共享数据结构实体来存放发送进程发送给接收进程的消息。发送者进程使用deposit将消息发送到信箱中,接收进程利用读取原语remove从信箱中取出对方发送给自己的消息。这时消息就被称为信件。每个信箱都有一个唯一的标识符,包含信箱头和信箱体两部分,信箱头包含信箱属性,格式,资源,互斥信号量,指向当前可存放信件位置的指针等。信箱体包含多个信格。
  私有信箱:由用户进程创建,只允许拥有信箱的进程读取信件,其他进程只能发送信件到这个信箱。
  共享信箱:拥有者和共享者都可以读取或发送信件到这个信箱。
  如果创建信箱的进程不需要这个信箱了,可以调用撤销信箱原语撤销该信箱,但公有信箱在系统运行期间始终存在。
  当然为了解决空信箱或者满信箱的问题,信箱通信采用如下同步规则:
  1)若发送信件时信箱已满,则发送进程应转变成等待信箱状态,直到信箱有空信格时才被唤醒;
  2)若取信件时信箱中已无信件,则接收进程转变为等待信件状态,直到有信件时才被唤醒。
  通信过程如下:
  1)接收者创建属于自己的私有信箱;
  2)发送者产生一个信件;
  3)发送者把信件投入接收者的私有信箱;(封装成投递原语deposit)
  4)接收者从自己的信箱中读取信件。(封装成读取原语remove)

四:死锁和饥饿

死锁:是由于多个·进程之间共享不可抢占资源,而使得彼此等待各自拥有的资源而都无法得到,因此一直阻塞的状态。
  死锁产生的四个必要条件
  1.互斥条件:进程对所获得的资源进行排他性使用,任一时刻一个资源仅被一个进程占用;
  2.请求和保持条件:一个进程请求资源得不到满足而阻塞自己时,并不释放自己已经拥有的资源,该条件也称为部分分配条件;
  3.不可抢占条件:进程所获得的资源在未使用完毕之前不能被其他进程抢占,而只能由占有该资源的进程自己释放;
  4.循环等待条件:若干进程形成一个循环等待链,链中每一个进程都在等待该链中下一个进程所占用的资源。
  不让死锁发生的策略通常采用两种途径:一种是静态的死锁预防,另一种是动态的,称为死锁避免
 4.1 死锁预防
  1.破坏“请求和保持”条件
   采用资源预分配策略,每个进程在运行之前一次性申请它所需要的全部资源,并在资源未得到满足之前不投入运行(就是得到所有资源之后,才运行),进程一旦运行,就不需要其他资源请求,使得请求条件不成立。
  2.破坏“不可抢占”条件
   采用抢占资源分配策略,进程在运行过程中根据需要逐个提出资源请求,当一个已经占有了某些资源的进程又提出新的资源请求而未得到满足时,则必须释放它已获得全部资源而进入阻塞状态,待以后需要时再重新申请,由于进程在阻塞时已释放了它所占有的全部资源,则可认为该进程所占用的资源被抢占了,从而破坏了不可抢占条件。
   3.破坏“循环等待”条件
    采用资源有序分配策略,将系统中所有资源进行编号,并规定进程申请资源时必须严格按照资源编号递增(或递增)的顺序进行。
 4.2 死锁避免
  在不改变资源分配策略的条件下,在每次分配资源的时候做一个例行检查,来根据检查结果决定是否分配资源。也就是允许进程动态申请资源,若不满足则进程阻塞,若满足则进行动态检查。检查的过程是先假定把资源分配给该进程,之后看此资源分配是否会使得系统处于不安全状态,若检查结果安全,才真正分配资源,若不安全,则取消此次分配资源并使得该进程处于阻塞状态。因此,死锁避免就是在动态检查的前提下动态分配资源,通过检查来阻止会导致进程进入死锁状态的资源分配,从而避免死锁发生。
4.3 死锁检测
 死锁的检测可以在进程提出资源请求时进行,也可以根据情况动态地检测死锁。采用资源分配图来检测化简:在资源分配图中找出一个非孤立也不会阻塞的进程结点(意味着可得到资源),那么就删除连接到该进程结点的所有请求边和分配边,使得它成为一个孤立结点。(孤立结点以为着这个进程得到了所有它需要的资源)。重复执行以上步骤,直到找不到满足孤立结点的进程结点为止。
 当死锁发生时,就意味着在资源分配图中,最终至少有两个非孤立结点,就说明进程各自占有自己的资源而等待对方的资源。
 死锁定理:某一时刻系统状态s为死锁状态的充分条件是:当且仅当S状态的资源分配图是不可完全化简的,此充分条件称为死锁定理。
 由此可得结论:

1.如果资源分配图中不存在环路,就说明系统是状态安全的,也就是不会发生死锁;
2.如果资源分配图中存在环路,并且每类资源节点中只有一个资源,则系统一定发生死锁,环路中的进程就是死锁进程。
3.如果资源分配图中存在环路,但所关联的资源结点有多个同类资源,那么这时环路的存在只是死锁发生的必要条件而不是充分条件。也就是说,系统发生死锁时,资源分配图必定出现环路,而系统资源图出现环路,则不一定发生死锁。

可采用死锁检测算法来检测死锁。
4.4 死锁解除
 常用的死锁解除的四个方法

1.撤销所有死锁进程:这是操作系统最常用也是复杂度最低的一种死锁解除方法。当检测到死锁进程时,直接撤销该进程并释放其占有的系统资源。
2.让死锁进程回撤到正常执行状态的某个检查点,然后重新启动所有进程,这种方法需要操作系统支持进程的回撤和重启,并且死锁仍可能发生;
3.按照某种顺序逐个撤销死锁进程,直到不再发生死锁为止。死锁进程撤销顺序通常是基于某种代价最小原则,而且每撤销一个进程后必须重新执行死锁检测算法;
4.采用抢占资源的策略直到不再发生死锁。这种方式也需要按照某种代价最小的原则进行资源抢占,而且每次抢占资源后需要重新执行死锁检测算法,以测试系统是否仍然存在死锁,这种方法复杂度最高。

死锁中的代价最小原则

1.到死锁发现时,消耗CPU时间最少;
2.到死锁发现时,获得系统资源的总量最少;
3.到死锁发现时,产生的输出量最少;
4.优先级最低;
5.预计进程的剩余时间最长。

五:Unix的并发机制

Unix为进程间的通信和同步提供了各种机制,主要包括:管道,消息,共享内存,信号量以及信号。其中,管道,消息和共享内存提供进程间传递数据的方法,而信号量和信号则用于触发其他进程的行为。
 5.1 管道
  管道是一个环形缓冲区,允许两个进程以生产者和消费者的模型进行通信。所以,这是一个先进先出的队列,有一个进程写入,而另一个进程读取。管道在创建时获得一个固定大小的字节数,当一个进程试图向管道中写时,若有足够空间,那么些请求被立即执行,否则阻塞该进程。如果一个读进程试图读取字节数大于当前管道中的字节数时,它也被阻塞,否则读取请求被立即执行。操作系统强制实施互斥,即一次只能有一个进程可以访问管道
  管道分为有名管道和无名管道,无名管道只有父子进程这种才可以共享管道,而不相关的进程只能共享有名管道。
 5.2 消息
  消息是有类型的一段文本,Unix为参与消息传递的进程提供msgsnd和msgrcv系统调用,每个进程都有一个与之相关的消息队列,其功能类似于信箱。
 5.3 共享内存
  共享内存是UNIX提供的进程间通信手段中速度最快的一种,这是虚存中由多个进程共享一个公共内存块。互斥约束不属于共享内存机制的一部分,但必须由使用共享内存的进程提供。
 5.4 信号量
  一个信号量包含:信号量的当前值、在信号量上操作的最后一个进程的进程ID、等待该信号量的值大于当前值的进程数以及等待该信号量的值为0的进程数
 5.5 信号
  信号是用于向一个进程通知发生异步事件的机制,信号类似于硬件中断,但没有优先级,即内核平等的对待所有信号,对于同时发生的信号,一次只给进程一个信号,而没有特定次序。
  进程间可以互相发送信号,内核也可以在内部发送信号。信号的传递是通过修改信号要发送到的进程对应的进程表中的一个域来完成的。只有进程被唤醒继续运行时,或者进程准备从系统调用中返回时,才处理信号。进程可以通过执行某些默认行为(终止进程)、执行一个信号处理函数或者忽略该信号来对信号做出响应。

六:LINUX内核并发机制

linux包含了管道、消息、共享内存和信号等并发机制,除此之外,还包含一套丰富的并发机制,这套机制是特别为内核态线程准备的。
 6.1 原子操作
  linux提供了一组操作以保证对变量的原子操作,这些操作用来避免简单的竞争条件。
 6.2 自旋锁
  在linux中保护临界区的最常见技术就是自旋锁,在同一时刻,只有一个线程能获得自旋锁,其他任何想获得自旋旋的线程将一直进行尝试(忙等,自旋),直到获得该锁。本质上,自旋锁建立在内存区的一个整数上,任何线程进入临界区之前必须检查该整数。如果该值为0,则线程设置该值为1,然后进入临界区。如果该值非0,则该线程继续检查该值,直到它为0。
  基本的自旋锁有4个版本:
  1.普通:临界区代码不被中断处理程序执行或在中断禁用的情况下,可以使用普通自旋锁,它不会影响当前处理器的中断状态。 
  2._irq:如果中断一直被启用,那么可以使用这种自旋锁;
  3._irqsave:如果不知道在执行时间内中断是否启用,那么可以使用这个版本,当获得锁时,本地处理器的中断状态就保存下来,当该锁释放时恢复状态。
  4._bh:当中断发生时,相应的中断处理器只处理最少量的工作,一段我们称之为下半部的代码执行中断相关工作的其他部分,这允许尽快的启用当前中断,_bh自旋锁用来禁用和启用下半部,以避免与临界区冲突。
  读者-写者自旋锁:该机制允许在内核中达到比基本的自旋锁更高的并发度。读者-写者自旋锁允许多个线程同时以只读的方式访问同一数据结构,只有当一个线程想要更高数据结构时,才会互斥的访问该自旋锁。如果自旋锁被读者拥有,那么写者就不能抢占该锁。 
 6.3 信号量
  内核的信号量不能通过系统调用来直接被用户程序访问。内核信号量是作为内核内部函数实现的,因此比用户可见的信号量更加高效。
  linux在内核中提供了三种信号量:二元信号量、计数信号量和读者-写者信号量。二元信号量在linux中又称为Mutex(互斥信号量)。
  读者-写者信号量将用户分为读者和写者,它允许多个并发的读者,但仅允许一个写者,事实上,对于读者使用的是一个计数信号量,而对于写者使用的是一个二元信号量(Mutex)。读者-写者信号量使用不可中断睡眠。
 6.4 屏障
  在一些体系结构中,编译器者处理器硬件为了优化性能,可能会对源代码中的内存访问重新排序,重新排序是为了优化对处理器指令流水线的使用。重新排序的算法包含相应的检查,以保证数据依赖不会发生冲突,但是有些代码不能重新排序,为了保证指令执行顺序,linux提供了内存屏障设施,来保证在某代码之前的代码没有任何读操作会穿过屏障,在某代码之后也是,同样对写操作也是类似的。

七:Solaris线程同步原语

除了UNIX的并发机制外,Solaris还支持四种线程同步原语:
  1.互斥锁
  2.信号量
  3.多读者单写者锁
  4.条件变量
 7.1 互斥锁
  互斥锁用于保证在同一时间只有一个线程能访问被互斥锁保护的资源。加锁互斥量的线程和解锁互斥量的线程必须是同一线程。默认的阻塞策略是一个自旋锁:一个被阻塞的线程在忙等循环中轮询锁的状态,还有一个基于中断的阻塞机制可供选择。对于后者,互斥量包含一个id用来标记在这个锁上睡眠的线程队列。
 7.2 信号量
  除了增加(解除阻塞)和减少(阻塞)信号量之外,还提供一个sem_tryp()来表示如果不要求阻塞,就减小信号量的原语,该原语允许忙等待。
 7.3 多读者-单写者锁
  该锁允许多个线程同时以只读权限访问锁中保护的对象,它还允许在排斥了所有读线程后,一次有一个线程作为写者访问该对象,当写者获得锁时,它呈现write lock状态:所有试图读或者写的线程都必须等待。如果一个或多个读线程获得了锁,则它的状态为read lock。
 7.4 条件变量
  条件变量用于等待一个特定的条件为真,它必须和互斥锁联合使用。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值