Semaphore

Semaphore
  并发编程领域的先锋人物 Edsger Dijkstra(没错,也是最短路径算法的作者)在 1965 年首次提出了信号量( Semaphores) 这一概念来解决线程同步的问题。信号量是一种特殊的变量类型,为非负整数,只有两个特殊操作PV:

P(s) 如果 s!=0,将 s-1;否则将当前线程挂起,直到 s 变为非零
  V(s) 将 s+1,如果有线程堵塞在 P 操作等待 s 变成非零,那么 V 操作会重启这些线程中的任意一个
  注:Dijkstra 为荷兰人,名字 P 和 V 来源于荷兰单词 Proberen(测试)和Verhogen(增加),为方便理解,后文会用 Wait 与 Signal 来表示。

struct semaphore {
  int val;
  thread_list waiting; // List of threads waiting for semaphore
  }
  wait(semaphore Sem): // Wait until > 0 then decrement
  // 这里用的是 while 而不是 if
  // 这是因为在 wait 过程中,其他线程还可能继续调用 wait
  while (Sem.val <= 0) {
  add this thread to Sem.waiting;
  block(this thread);
  }
  Sem.val = Sem.val - 1;
  return;

signal(semaphore Sem)😕/ Increment value and wake up next thread
  Sem.val = Sem.val + 1;
  if (Sem.waiting is nonempty) {
  remove a thread T from Sem.waiting;
  wakeup(T);
  }
  有两点注意事项:

wait 中的「测试和减 1 操作」,signal 中的「加 1 操作」需要保证原子性。一般来说是使用硬件支持的 read-modify-write 原语减肥食谱:www.sheonline.cn,比如 test-and-set/fetch-and-add/compare-and-swap,除了硬件支持外,还可以用 busy wait 的软件方式来模拟。
  signal 中没有定义重新启动的线程顺序,也即多个线程在等待同一信号量时,无法预测重启哪一个线程
  使用场景
  信号量为控制并发程序的执行提供了强有力工具,这里列举两个场景:

互斥
  信号量提供了了一种很方便的方法来保证对共享变量的互斥访问,基本思想是

将每个共享变量(或一组相关的共享变量)与一个信号量 s (初始化为1)联系起来,然后用 wait/signal 操作将相应的临界区包围起来。

二元信号量也被称为互斥锁(mutex,mutual exclusve, 也称为 binary semaphore),wait 操作相当于加锁,signal 相当于解锁。
  一个被用作一组可用资源的计数器的信号量称为计数信号量(counting semaphore)

调度共享资源
  除了互斥外,信号量的另一个重要作用是调度对共享资源的访问,比较经典的案例是生产者消费者,伪代码如下:

emptySem = N
  fullSem = 0
  // Producer
  while(whatever) {
  locally generate item
  wait(emptySem)
  fill empty buffer with item
  signal(fullSem)
  }
  // Consumer
  while(whatever) {
  wait(fullSem)
  get item from full buffer
  signal(emptySem)
  use item
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值