zoukankan      html  css  js  c++  java
  • 信号量的基本同步模式

    信令

    一个线程向另一个线程发送信号,以通知它发生了某些事情。它完成了一个执行顺序的约束,解决了所谓的序列化问题。

    集合点

    考虑线程 A 的两个语句 A1,A2,线程 B 的两个语句 B1,B2。我们要求 A2 必须在 B1 后发生,B2 必须在 A1 后发生。换言之,A 必须等待 B,B 也必须等待 A,只有在它们都执行完步 1 后才能执行步 2。

    因此,设计两个信号量 aX 表示线程 A 到达了集合点,bX 表示线程 B 到达了集合点。那么 A 发送 aX 并等待 bX 才继续执行,B 发送 bX 并等待 aX 才继续执行。

    注意,发送一定要放在等待之前,否则可能会导致死锁。

    互斥

    考虑如何通过信号量来实现对一个变量的互斥访问。

    为每个互斥变量安排一个信号量 m,初态为 1,所有访问这个变量的代码都应该套上 m.wait() 在前而 m.signal() 在后。

    多路复用

    类似互斥,但允许多个线程同时在临界区内执行,并强制给定一个并发线程数的上限。

    为每个多路复用区安排一个信号量 m,初态为其数量限制,所有访问这临界区的代码都应该套上 m.wait() 在前而 m.signal() 在后。

    屏障

    我们从集合点模式出发做一些推广。现在有很多个线程,每个线程都执行两个步骤 rendezvous 和 critical,我们需要保证只要有任何一个线程未完成第一步,就不存在任何一个线程进入第二步。

    这里我们需要两个部分,一个自带互斥锁的计数器 count 和一个标识屏障是否被推倒的信号量 bar

    思路非常清晰,每个线程执行完 rendezvous 后修改计数器,如果计数器等于 n 则推倒屏障。如果只推倒一次是有问题的。两种解决方案:要么连续推倒 n 次,要么在每个线程等待屏障等到后再次推倒屏障。

    rendezvous
    m.wait()
    	count++
    m.signal()
    if count==n: bar.signal()
    bar.wait()
    bar.signal()
    critical
    

    这里出现了一种新模式:快速连续的 wait 和 signal,我们将它称作旋转门。它一次只允许一个线程通过。它可以锁定以组织所有线程。

    在本例中,初态下旋转门被锁定。第 n 个到达的线程将解锁它,然后 n 个线程将都可以通过。

    可重用屏障

    现在我们希望在所有线程都通过屏障后,再次锁定旋转门。

    考虑到代码可能会循环执行,为了防止某些 HKJ 线程搞事情,我们设置两个旋转门 ts1,ts2。最初第一个被锁定,第二个被打开。当所有线程到达第一个时,我们锁定第二个并解锁第一个。对第二个也同理。

    rendezvous
    m.wait()
    	cnt++
    	if cnt==n: ts2.wait(), ts1.signal()
    m.signal()
    ts1.wait()
    ts1.signal()
    critical
    m.wait()
    	cnt--
    	if cnt==0: ts1.wait(), ts2.signal()
    m.signal()
    ts2.wait()
    ts2.signal()
    

    另一个方案是连续推倒 n 次。

    rendezvous
    m.wait()
    	cnt++
    	if cnt==n: ts1.signal(n)
    m.signal()
    ts1.wait()
    critical
    m.wait()
    	cnt--
    	if cnt==0: ts2.signal(n)
    m.signal()
    ts2.wait()
    

    我们以后可以将这种屏障模式描述为一个固定的类封装形式。

    bar=Barrier(n)
    bar.wait()
    

    队列

    这里说的队列是这样的:领袖和粉丝配对跳舞。当领袖到达时,会检查是否有粉丝在等待。如果有,他们就结伴然后干一些什么事,没有的话就抽根烟等一等。

    我们需要两个信号量 lQfQ 来标识领袖等待的数量和粉丝等待的数量。这里似乎只是一个可以重叠的集合点,因此对领袖而言,我们有

    fQ.signal()
    lQ.wait()
    dance()
    

    独占队列

    现在我们在队列问题的基础上,增加一个约束条件,每个领袖只能与一个粉丝同时调用 dance,换言之这个 dance 的调用必须由领袖和粉丝不断地交替进行。

    对于领袖而言

    m.wait()
    if fCnt>0: fCnt--, fQue.signal()
    else: lCnt++, m.signal(), lQue.wait()
    dance()
    rendezvous.wait()
    m.signal()
    

    对于粉丝而言

    m.wait()
    if lCnt>0: lCnt--, lQue.signal()
    else: fCnt++, m.signal(), fQue.wait()
    dance()
    rendezvous.signal()
    

    当一个领袖到达时,如果已经有等待的粉丝就唤醒他并开始跳舞,否则进入等待。最后的 rendezvous 是为了保证在本次配对结束前,不能有新的人打开互斥锁。

  • 相关阅读:
    ArcGIS Pro获得一个要素图层一种方法
    ArcGIS Pro layout clone
    ActiveMapViewChanged和选择变化
    ArcGIS Pro 改变栅格的数据源
    ArcGIS Pro自定义图标
    Windows Server 2016 路由和远程访问
    IIS应用程序池_缓存回收
    asp.net RSA密钥之C#格式与Java格式转换(PEM格式)
    MD5和Hash
    C# list与数组的转换
  • 原文地址:https://www.cnblogs.com/mollnn/p/14885324.html
Copyright © 2011-2022 走看看