信号量
Semaphore(信号量)是一个线程同步结构,用于在线程间传递信号,以避免出现信号丢失(译者注:下文会具体介绍),或者像锁一样用于保护一个关键区域。自从 5.0 开始,jdk 在 java.util.concurrent 包里提供了 Semaphore 的官方实现,因此大家不需要自己去实现 Semaphore。但是还是很有必要去熟悉如何使用 Semaphore 及其背后的原理
本文的涉及的主题如下:
- 简单的 Semaphore 实现
- 使用 Semaphore 来发出信号
- 可计数的 Semaphore
- 有上限的 Semaphore
- 把 Semaphore 当锁来使用
简单的 Semaphore 实现
下面是一个信号量的简单实现:
public class Semaphore {
private boolean signal = false;
public synchronized void take() {
this.signal = true;
this.notify();
}
public synchronized void release() throws InterruptedException{
while(!this.signal) wait();
this.signal = false;
}
}
Take 方法发出一个被存放在 Semaphore 内部的信号,而 Release 方法则等待一个信号,当其接收到信号后,标记位 signal 被清空,然后该方法终止。
使用这个 semaphore 可以避免错失某些信号通知。用 take 方法来代替 notify,release 方法来代替 wait。如果某线程在调用 release 等待之前调用 take 方法,那么调用 release 方法的线程仍然知道 take 方法已经被某个线程调用过了,因为该 Semaphore 内部保存了 take 方法发出的信号。而 wait 和 notify 方法就没有这样的功能。
当用 semaphore 来产生信号时,take 和 release 这两个方法名看起来有点奇怪。这两个名字来源于后面把 semaphore 当做锁的例子,后面会详细介绍这个例子,在该例子中,take 和 release 这两个名字会变得很合理。
使用 Semaphore 来产生信号
下面的例子中,两个线程通过 Semaphore 发出的信号来通知对方
Semaphore semaphore = new Semaphore();
SendingThread sender = new SendingThread(semaphore);
ReceivingThread receiver = new ReceivingThread(semaphore);
receiver.start();
sender.start();
public class SendingThread {
Semaphore semaphore = null;
public SendingThread(Semaphore semaphore){
this.semaphore = semaphore;
}
public void run(){
while(true){
//do something, then signal
this.semaphore.take();
}
}
}
public class RecevingThread {
Semaphore semaphore = null;
public ReceivingThread(Semaphore semaphore){
this.semaphore = semaphore;
}
public void run(){
while(true){
this.semaphore.release();
//receive signal, then do something...
}
}
}
可计数的 Semaphore
上面提到的 Semaphore 的简单实现并没有计算通过调用 take 方法所产生信号的数量。可以把它改造成具有计数功能的 Semaphore。下面是一个可计数的 Semaphore 的简单实现。
public class CountingSemaphore {
private int signals = 0;
public synchronized void take() {
this.signals++;
this.notify();
}
public synchronized void release() throws InterruptedException{
while(this.signals == 0) wait();
this.signals--;
}
}
有上限的 Semaphore
上面的 CountingSemaphore 并没有限制信号的数量。下面的代码将 CountingSemaphore 改造成一个信号数量有上限的 BoundedSemaphore。
public class BoundedSemaphore {
private int signals = 0;
private int bound = 0;
public BoundedSemaphore(int upperBound){
this.bound = upperBound;
}
public synchronized void take() throws InterruptedException{
while(this.signals == bound) wait();
this.signals++;
this.notify();
}
public synchronized void release() throws InterruptedException{
while(this.signals == 0) wait();
this.signals--;
this.notify();
}
}
在 BoundedSemaphore 中,当已经产生的信号数量达到了上限,take 方法将阻塞新的信号产生请求,直到某个线程调用 release 方法后,被阻塞于 take 方法的线程才能传递自己的信号。
把 Semaphore 当锁来使用
当信号量的数量上限是 1 时,Semaphore 可以被当做锁来使用。通过 take 和 release 方法来保护关键区域。请看下面的例子:
BoundedSemaphore semaphore = new BoundedSemaphore(1);
...
semaphore.take();
try{
//critical section
} finally {
semaphore.release();
}
在前面的例子中,Semaphore 被用来在多个线程之间传递信号,这种情况下,take 和 release 分别被不同的线程调用。但是在锁这个例子中,take 和 release 方法将被同一线程调用,因为只允许一个线程来获取信号(允许进入关键区域的信号),其它调用 take 方法获取信号的线程将被阻塞,知道第一个调用 take 方法的线程调用 release 方法来释放信号。对 release 方法的调用永远不会被阻塞,这是因为任何一个线程都是先调用 take 方法,然后再调用 release。
通过有上限的 Semaphore 可以限制进入某代码块的线程数量。设想一下,在上面的例子中,如果 BoundedSemaphore 上限设为 5 将会发生什么?意味着允许 5 个线程同时访问关键区域,但是你必须保证,这个 5 个线程不会互相冲突。否则你的应用程序将不能正常运行。
必须注意,release 方法应当在 finally 块中被执行。这样可以保在关键区域的代码抛出异常的情况下,信号也一定会被释放。
相关推荐
### c语言信号量的使用实例 #### 一、信号量的基本概念 信号量是一种用于解决进程间同步问题的机制,在多线程或多进程环境中尤为重要。它通过控制共享资源的访问来避免竞态条件,确保数据的一致性。信号量本质上是...
信号量(Semaphore)是实现多线程同步的一种有效工具,常用于控制对共享资源的访问。在这个名为"Mthread11"的MFC工程中,我们可以看到如何在C++环境中应用信号量来解决多线程间的同步问题。 首先,我们需要理解什么...
"信号量的应用" 信号量是一种在多线程环境下使用的设施,用于保证两个或多个关键代码段不被并发调用。信号量的作用类似于一个看门人,控制着公共资源的访问,确保资源的安全使用。 信号量的特性可以抽象地认为是一...
为此,定义了三个接收信号量S2、S3、S4,P1发送一条消息前会检查这三个信号量,确保每个接收进程都已做好准备。 第四个问题涉及三个进程共享表格F,其中P1只读,P2只写,P3先读后写。这里使用了两个信号量Rmutex和...
硬件信号量模块由64个独立的信号量组成,这些信号量不与硬件资源或核直接绑定,而是根据每个核处理任务的负载进行动态分配。硬件信号量的访问方式包括直接访问、间接访问和查询方式,这三种方式在软件层面上的实现都...
3. **信号量的创建与操作**:学习如何使用`OSSemaphoreCreate`创建信号量,`OSSemaphorePend`获取信号量(等待),以及`OSSemaphorePost`释放信号量(唤醒等待的任务)。 4. **任务间通信**:通过信号量,不同任务...
理发师问题-信号量PV操作实现 本文探讨了理发师问题的解决方案,该问题是一个经典的多进程同步问题。通过使用信号量PV操作,实现了多线程同步,解决了理发师问题。下面是该解决方案的详细介绍。 信号量PV操作 ...
"holecev"可能是作者或项目的别名,而"RT-Thread_rtthread信号量_信号量_"则是强调了这个资料主要关注RT-Thread中的信号量机制。 信号量在RT-Thread中的应用主要包括以下方面: 1. **同步**:当多个线程需要协同...
信号量是一种在多任务操作系统中实现资源管理和任务同步的重要机制,尤其在嵌入式系统如UCOSii中广泛应用。本文将深入探讨信号量的理解、其有效性、相关函数以及互斥型信号量及其带来的优先级反转问题。 首先,UCOS...
`semget`用于创建信号量集,`semop`执行信号量操作(如P(等待)和V(释放)操作),`semctl`用于管理信号量集,如初始化或删除。 在实际应用中,信号量常与共享内存结合使用,确保对共享内存的访问是同步的。例如...
UCOS-II学习笔记——信号量集(事件标志组)的原理及使用 UCOS-II操作系统中的信号量集(事件标志组)是一种同步机制,用于控制任务之间的同步和通信。信号量集是UCOS-II操作系统中的一个重要组件,用于协调多个...
操作系统是计算机科学中的核心课程,而信号量是操作系统中一种重要的同步机制,它在多进程或多线程环境下用于协调共享资源的访问。哈工大软件学院的操作系统实验4聚焦于信号量的实现与应用,旨在让学生深入理解并...
信号量分为两种类型:整型信号量和记录型信号量。整型信号量只包含一个整数值,而记录型信号量则包含一个整数值和一个等待队列。在本实验中,你可能会使用PV操作来管理共享资源的访问,确保并发进程的正确调度。 总...
labview,2018,信号量__获取信号量_释放信号量
信号量机制是操作系统中一种重要的同步工具,常用于解决多线程环境中的资源竞争问题。本问题中,通过“爸爸放苹果,妈妈放橘子,盘子只能容纳两个水果。儿子只吃苹果,女儿只吃橘子”的情景,我们可以深入理解信号量...
本文将深入探讨标题"19,信号量_rtthread_STM32F103_RTT_信号量_"所涉及的关键知识点,包括RT-Thread(RTT)在STM32F103微控制器上的应用,以及信号量的两种主要类型:二值信号量和计数信号量。 首先,RT-Thread是...
4. **信号量操作**:有三个主要的信号量操作:`OSSemPend()`用于获取信号量,如果信号量不可用,则任务会被挂起;`OSSemPost()`用于释放信号量,增加信号量的计数值;`OSSemDel()`用于删除不再使用的信号量。 5. **...
在QT框架中,信号量(Semaphore)是一种非常重要的同步机制,它源于进程间通信(IPC)的概念,并在多线程编程中广泛使用。信号量允许我们控制对共享资源的访问,确保同一时间只有一个线程或者有限数量的线程能够访问...
这种信号量主要用于资源的互斥访问,即在任何时刻只有一个任务可以持有信号量。当一个任务获取到信号量时,信号量状态变为被占用;当任务完成对资源的访问后,必须释放信号量,让其他任务有机会获取。 在FreeRTOS中...
信号量值可以用来表示资源的可用数量,当线程试图获取一个资源时,如果信号量值大于零,那么线程可以继续执行并减少信号量值;如果信号量值为零,则线程会被阻塞,直到其他线程释放资源,信号量值增加。 首先,我们...