进程通信 (信号量,管程),以及生产者消费者模型

信号量

P(): sem 减一

V():sem+1

  • 一个是 P 操作,这个操作会把信号量减去 1,相减后如果信号量 < 0,则表明资源已被占用,进程需阻塞等待;相减后如果信号量 >= 0,则表明还有资源可使用,进程可正常继续执行。

  • 另一个是 V 操作,这个操作会把信号量加上 1,相加后如果信号量 0,则表明当前没有阻塞中的进程;

P 操作是用在进入共享资源之前,V 操作是用在离开共享资源之后,这两个操作是必须成对出现的。

接下来,举个例子,如果要使得两个进程互斥访问共享内存,我们可以初始化信号量为 1

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/10-%E4%BF%A1%E5%8F%B7%E9%87%8F-%E4%BA%92%E6%96%A5.jpg

具体的过程如下:

  • 进程 A 在访问共享内存前,先执行了 P 操作,由于信号量的初始值为 1,故在进程 A 执行 P 操作后信号量变为 0,表示共享资源可用,于是进程 A 就可以访问共享内存。

  • 若此时,进程 B 也想访问共享内存,执行了 P 操作,结果信号量变为了 -1,这就意味着临界资源已被占用,因此进程 B 被阻塞。

  • 直到进程 A 访问完共享内存,才会执行 V 操作,使得信号量恢复为 0,接着就会唤醒阻塞中的线程 B,使得进程 B 可以访问共享内存,最后完成共享内存的访问后,执行 V 操作,使信号量恢复到初始值 1。

可以发现,信号初始化为 1,就代表着是互斥信号量,它可以保证共享内存在任何时刻只有一个进程在访问,这就很好的保护了共享内存。

另外,在多进程里,每个进程并不一定是顺序执行的,它们基本是以各自独立的、不可预知的速度向前推进,但有时候我们又希望多个进程能密切合作,以实现一个共同的任务。

例如,进程 A 是负责生产数据,而进程 B 是负责读取数据,这两个进程是相互合作、相互依赖的,进程 A 必须先生产了数据,进程 B 才能读取到数据,所以执行是有前后顺序的。

那么这时候,就可以用信号量来实现多进程同步的方式,我们可以初始化信号量为 0

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/11-%E4%BF%A1%E5%8F%B7%E9%87%8F-%E5%90%8C%E6%AD%A5.jpg

具体过程:

  • 如果进程 B 比进程 A 先执行了,那么执行到 P 操作时,由于信号量初始值为 0,故信号量会变为 -1,表示进程 A 还没生产数据,于是进程 B 就阻塞等待;

  • 接着,当进程 A 生产完数据后,执行了 V 操作,就会使得信号量变为 0,于是就会唤醒阻塞在 P 操作的进程 B;

  • 最后,进程 B 被唤醒后,意味着进程 A 已经生产了数据,于是进程 B 就可以正常读取数据了。

可以发现,信号初始化为 0,就代表着是同步信号量,它可以保证进程 A 应在进程 B 之前执行。

初始值可以设置为0,当火车进入之前,执行p-操作,然后走了之后,执行v+操作,使的后面的阻塞进程被告知可以进入

生产者消费者

临界资源mutex设置为1,空资源空间设置为n,满空间为0

流程是

1.生产者先把empty--;然后进去临界区,mutex 为0,可以进入,但是消费者不能干预,所以添加数据,退出临界区的时候,mutex+1,使得消费者可以进入,然后full+1,表示增加了一个资源

2.消费者首先把full-1,然后进入临界资源,将数据取出,然后退出临界资源,empty+1;


管程

生产者消费,进去直接锁,互斥

发出唤醒的线程和被唤醒的线程谁执行?

1.第一个睡眠,被唤醒的直接占用cpu执行

2.第一个执行完relase lock 才给第二个被唤醒的线程

当一个线程在管程中等待某个条件时,它释放对管程的锁定并进入等待状态。这时,管程中的其他线程可以继续执行。当条件满足时,需要唤醒等待的线程。管程中的两种常见唤醒线程的方法如下:

方法一:被唤醒的线程直接占用 CPU 执行

  1. 线程 A 进入管程并等待某个条件,例如等待一个共享资源可用。

  2. 线程 B 获得管程的锁定并修改了共享资源,然后通知条件满足。

  3. 管程唤醒等待的线程 A。

  4. 线程 A 被唤醒后重新获得管程的锁定,并开始执行。它会检查条件是否满足,如果满足,则继续执行相关操作,否则可能再次进入等待状态。

方法二:等待的线程等待第一个线程释放锁定后才被唤醒

  1. 线程 A 进入管程并等待某个条件,释放管程的锁定并进入等待状态。

  2. 线程 B 获得管程的锁定,并修改了共享资源,然后通知条件满足。

  3. 管程唤醒等待的线程 A,但线程 A 不立即执行。

  4. 线程 B 完成对共享资源的修改后,释放管程的锁定。

  5. 被唤醒的线程 A 获得管程的锁定并开始执行。它会检查条件是否满足,如果满足,则继续执行相关操作,否则可能再次进入等待状态。

在方法二中,被唤醒的线程不会立即执行,而是等待第一个线程释放锁定后才被唤醒并获得锁定。这样可以避免不必要的上下文切换和竞争,但可能会导致一些等待时间。具体使用哪种方法取决于编程语言、操作系统和具体的应用场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值