操作系统 Semaphore介绍
在本教程中,我们将学习最重要的主题之一,即Semaphore。可以百分之百确认的是,在面试、考试和甚至招聘考试中都会涉及Semaphore这个主题的问题。因此,请务必仔细理解和重视这个主题。
在本主题中,我们将学习Semaphore定义、Semaphore的类型、Semaphore的操作、Semaphore的优缺点,使用Semaphore解决经典同步问题的过程以及在解决这些经典同步问题中使用这些类型的Semaphore。
Semaphore定义
Semaphore是一种硬件解决方案。这个硬件解决方案被用于解决临界区问题。
临界区问题是什么
临界区问题是一段代码片段。这段代码片段包含一些变量。这些变量可以被一些进程访问。对于这些进程,有一个条件。
这个条件是只有一个进程可以进入临界区。其余想要进入临界区的进程必须等待进程完成工作,然后才能进入临界区。
临界区的表示
临界区问题
可能存在一个或多个进程尝试进入临界区的状态。在多个进程进入临界区后,第二个进程尝试访问被第一个进程已经访问过的变量。
解释
假设存在一个也被称为共享变量的变量。让我们定义这个共享变量。
在这里,x是共享变量。
int x = 10;
Process 1
// Process 1
int s = 10;
int u = 20;
x = s + u;
Process 2
// Process 2
int s = 10;
int u = 20;
x = s - u;
如果进程连续访问共享变量x,那么我们就会处于一个好的位置。
如果只有Process 1执行,那么x的值为x = 30;
共享变量x从10变为30。
如果只有Process 2执行,那么x的值为x = -10;
共享变量x从30变为-10。
如果两个进程同时发生,那么编译器将无法选择哪个变量值,即-10或30。变量x所面临的状态称为数据不一致性。这些问题也可以通过硬件锁来解决。
为了防止这种问题,可以通过名为信号量的硬件解决方案进行解决。
信号量
信号量只是一个普通的整数。信号量不能为负数。信号量的最小值是零(0)。信号量的最大值可以是任何值。信号量通常具有两个操作。这两个操作能够确定信号量的值。
这两个信号量操作是:
- 等待(Wait)
- 信号(Signal)
等待信号量操作
等待操作用于确定进程进入临界状态的条件或等待进程执行。在这里,等待操作有许多不同的名称。不同的名称有:
- 睡眠操作
- 下降操作
- 减少操作
- P函数(等待操作的最重要的别名)
等待操作基于信号量或互斥值的基础上工作。
在这里,如果信号量的值大于零或正数,则进程可以进入临界区域。
如果信号量的值等于零,则进程必须等待进程退出临界区域。
此函数仅在进程进入临界状态之前存在。如果进程进入了临界状态,那么P函数或等待操作就没有工作要做。
如果进程退出临界区域,我们必须减少信号量的值。
P函数或等待操作的基本算法
P (Semaphore value)
{
Allow the process to enter if the value of Semaphore is greater than zero or positive.
Do not allow the process if the value of Semaphore is less than zero or zero.
Decrement the Semaphore value if the Process leaves the Critical State.
}
信号量操作
信号量操作用于更新信号量的值。新的进程准备进入临界区时,信号量的值会被更新。
信号操作也被称为:
- 唤醒操作
- 增加操作
- 提升操作
- V 函数(最重要的别名)
我们知道,在等待操作中,当进程离开临界状态时,信号量的值会减小1。为了抵消减小的1,我们使用信号操作来增加信号量的值。这样,临界区就能接收更多的进程。
最重要的部分是,信号操作或V函数仅在进程从临界区退出时执行。在进程从临界区退出之前,信号量的值不能被递增。
V函数或信号操作的基本算法
V (Semaphore value)
{
If the process goes out of the critical section then add 1 to the semaphore value
Else keep calm until process exits
}
信号量的类型
信号量有两种类型。
他们是:
1. 二元信号量
在二元信号量的概念中,信号量只有两个值。这两个值分别为 1 和 0。
如果二元信号量的值为 1,那么进程有进入临界区域的能力。如果二元信号量的值为 0,则进程没有进入临界区域的能力。
2. 计数信号量
在计数信号量的概念中,信号量有两组值。一组是大于或等于 1 的值,另一组是等于 0 的值。
如果计数信号量的值大于或等于 1,那么进程有进入临界区域的能力。如果计数信号量的值为 0,则进程没有进入临界区域的能力。
这是关于二元信号量和计数信号量的简要描述。在下一篇文章中,您将会更加深入地学习它们。
信号量的优点
- 信号量是机器无关的,因为它们的实现和代码是写在微内核的机器无关代码区域中的。
- 它们严格执行互斥并允许进程以一次一个的方式进入关键部分(仅适用于二元信号量的情况)。
- 使用信号量,不会因为忙等待而丢失资源,因为我们不需要任何处理器时间来验证在允许进程访问关键区域之前是否满足某个条件。
- 信号量对资源的管理非常好。
- 它们禁止多个进程进入关键区域。它们比其他同步方法更有效,因为通过这种方式可以实现互斥。
信号量的缺点
- 由于使用信号量,高优先级进程有可能在低优先级进程之前进入关键区域。
- 由于信号量的一定复杂性,需要以避免死锁的方式来设计等待和通知操作。
- 编写信号量是非常具有挑战性的,存在互斥无法实现的风险。
- 必须按照适当的顺序执行等待(wait)和通知(signal)操作,以防止死锁。
现在,让我们使用信号量的概念来解决经典的同步问题。
使用信号量概念解决经典同步问题
1. 使用信号量解决读者 – 写者问题
定义:
首先,让我们了解一下读者 – 写者问题。
在读者 – 写者问题中,有两个参与者。他们是读者和写者。读者 – 写者问题试图访问或更改共享变量的值。由于并行执行访问和更改操作的数据故障发生。因此,预期的输出与实际输出不符。这就是读者 – 写者问题。
读者和写者的责任是不同的。
读者任务是读取共享变量的值。
写者任务是改变共享变量的值。
现在,让我们借助一个信号量来解决这个问题。
所需数据
首先,让我们考虑一个包含共享变量的临界区。假设有两个进程。第一个进程总是试图访问共享变量。第二个进程总是试图改变变量的值。
解决方案
现在,让我们借助二进制信号量来解决读者-写者问题。
现在,我们的任务是使用信号量执行读者和写者的操作,而不会发生死锁。
借助二进制信号量解决读者-写者问题的算法
/* Process 1 - - - > Reader
Process 2 - - - > Writer */
Solving (int n)
{
if (n==0)
{
//You cannot enter the critical section area.
}
if (n==1)
{
Enter the process which you want to perform
scan (op)
if (op==1)
{
Read ( )
} // read
else if (op==2)
{
Write ( )
} // write
} // if condition for entering critical section
} // Solving
Main ( )
{
do
{
{
Process (Semaphore)
// Enter the Entry section if the Semaphore value is one.
Entry Section
Critical Section
Exit Section
} // Entry Section
} // main
使用计数信号量解决读者 – 写者问题
我们知道,如果计数信号量的值大于或等于1,进程就可以进入临界区。
现在,我们将允许写者在计数信号量的值大于或等于1时工作或执行其任务。这样可以保证数据的更改是无误的。
如果计数信号量的值大于或等于1,或者计数信号量的值等于0,我们可以允许读者工作或执行其任务。这是因为读者只是读取共享变量的值。但根据信号量的规则,只有计数信号量的值大于或等于1时,我们才能进入临界区。
因此,如果计数信号量的值大于或等于1,我们可以允许读者进入。
使用二进制信号量解决读者 – 写者问题的算法
/* Process 1 - - - > Reader
Process 2 - - - > Writer */
Solving (int n)
{
if (n==0)
{
//You cannot enter the critical section area.
}
if (n>=1)
{
Enter the process which you want to perform
scan (op)
if (op==1)
{
Read ( )
} // read
else if (op==2)
{
Write ( )
} // write
} // if condition for entering critical section
} // Solving
Main ( )
{
do
{
Process (Semaphore)
// Enter the Entry section if the Semaphore value is greater or equal to one.
Entry Section
Critical Section
Exit Section
Remainder Section
} // do
while (true);
} // Entry Section
} // main
2. 使用信号量的概念解决有界缓冲区问题
定义:
生产者-消费者问题是有界缓冲区问题的另一个名称。在这个问题中,缓冲区中有n个槽位,每个槽位可以容纳一个数据单元。生产者和消费者是使用缓冲区的两个操作。生产者和消费者都尝试进入和删除数据。
解决方案:
现在,我们将要解决有界缓冲区问题或生产者消费者问题中面临的问题。
我们已经知道生产者的任务是在任何可用区域中输入数据。
消费者的任务是删除生产者产生的数据或已经存在的数据。
现在,让我们了解这两个生产者和消费者是如何与二进制和计数信号量的概念一起工作的。
使用二进制信号量解决有界缓冲区或生产者消费者问题
我们知道,如果二进制信号量的值为1,进程可以进入临界区。
现在,我们将允许编写者在二进制信号量值为1时工作或执行任务。这样可以保证数据的变化是无错误的。
现在,假设生产者在临界区创建了一些共享变量。
现在,让我们允许名称为Producer的进程并在进入临界区后,在临界区内产生新值。只有当二进制信号量的值等于1时,才接受进入。
现在,让我们允许名称为Consumer的进程并在进入临界区后删除创建的进程。只有当二进制信号量的值等于1时,才接受进入。
现在,我们的任务是防止生产者和消费者同时执行。因此,我们给用户或计算机一个选择选择在输入临界区的入口节中执行哪个操作。
使用计数信号量解决有界缓冲区或生产者消费者问题
我们知道,如果计数信号量的值为1或大于1,进程可以进入临界区。
现在,我们将允许编写者在计数信号量的值为1或大于1时工作或执行任务。这样可以保证数据的变化是无错误的。
现在,假设生产者在临界区创建了一些共享变量。
现在,让我们允许名称为Producer的进程并在进入临界区后,在临界区内产生新值。只有当计数信号量的值等于或大于1时,才接受进入。
现在,让我们允许名称为Consumer的进程并在进入临界区后删除创建的进程。只有当计数信号量的值为1或大于1时,才接受进入。
现在,我们的任务是防止生产者和消费者同时执行。因此,我们给用户或计算机一个选择选择在输入临界区的入口节中执行哪个操作。
3. 使用信号量的概念解决餐厅哲学家问题
定义:
餐桌哲学家的困境,也被称为传统的同步问题,有五个坐在圆桌旁边的哲学家,他们必须在思考和进餐之间交替。桌子中央有一碗面条和五根筷子,每个哲学家一根。哲学家必须同时使用右手和左手的筷子才能吃饭。只有当哲学家的左手和右手筷子都能够触及时,哲学家才能进餐。如果哲学家的左手和右手筷子不能立即使用,哲学家会放下其中一根筷子(左手或右手)并继续思考。
餐桌哲学家是一个经典的同步问题,因为它展示了广泛的并发控制问题类别。
现在,您可能已经了解了信号量在解决同步过程所带来的问题中的用途。
这就是操作系统中信号量的全部内容。