互斥量 vs 信号量

2025年4月23日 | 阅读 6 分钟

根据操作系统术语,互斥锁和信号量是提供同步服务的内核资源,也称为同步原语。进程同步在保持共享数据的一致性方面起着重要作用。软件和硬件解决方案都存在用于处理临界区问题。但硬件解决方案对于临界区问题来说相当难以实现。互斥锁和信号量都提供同步服务,但它们并不相同。

什么是互斥锁?

互斥锁是一个互斥对象,用于同步对资源的访问。它在程序开始时以唯一名称创建。互斥锁锁定机制确保只有一个线程可以获取互斥锁并进入临界区。该线程仅在退出临界区时释放互斥锁。

Mutex vs Semaphore

它是一种特殊的二元信号量,用于控制对共享资源的访问。它包含优先级继承机制,以避免扩展的优先级反转问题。它允许当前高优先级任务被阻塞的时间尽可能短。然而,优先级继承并不能纠正优先级反转,而只能最小化其影响。

示例

这可以通过以下示例说明,

互斥锁的使用

互斥锁提供互斥,生产者或消费者都可以拥有密钥(互斥锁)并继续进行工作。只要生产者填满缓冲区,用户就需要等待,反之亦然。在互斥锁模式下,任何时候只有一个线程可以处理整个缓冲区。

当程序启动时,它请求系统为给定资源创建一个互斥锁对象。系统使用唯一名称或 ID 创建互斥锁对象。每当程序线程想要使用该资源时,它就会锁定互斥锁对象,利用该资源,并在使用后,释放互斥锁对象上的锁。然后,下一个进程才允许获取互斥锁对象上的锁。

与此同时,当一个进程获取了互斥锁对象上的锁时,没有其他线程或进程可以访问该资源。如果互斥锁对象已被锁定,则希望获取互斥锁对象上锁的进程必须等待,并被系统排队,直到互斥锁对象被解锁。

互斥锁的优点

互斥锁的一些优点如下:

  • 互斥锁只是一个简单的锁,在进入临界区之前获取,然后释放。
  • 由于任何时候只有一个线程在其临界区内,因此不会出现竞态条件,数据始终保持一致。

互斥锁的缺点

互斥锁也有一些缺点,例如:

  • 如果一个线程获取了锁然后休眠或被抢占,那么另一个线程可能无法继续。这可能导致饥饿。
  • 它不能从与获取它的上下文不同的上下文中锁定或解锁。
  • 任何时候只允许一个线程进入临界区。
  • 正常实现可能导致忙等待状态,这会浪费 CPU 时间。

什么是信号量?

信号量只是一个在线程之间共享的非负变量。信号量是一种信号机制,另一个线程可以向正在等待信号量的线程发出信号。

Mutex vs Semaphore

信号量使用两个原子操作:

1. Wait (等待):如果其参数 S 为正,则 Wait 操作会减少 S 的值。如果 S 为负或零,则不执行任何操作。

2. Signal (信号,用于进程同步):Signal 操作会增加其参数 S 的值。

信号量根据其设置方式,允许或拒绝对资源的访问。

信号量的使用

在单个缓冲区的情况下,我们可以将 4 KB 的缓冲区分成四个 1 KB 的缓冲区。信号量可以与这些缓冲区关联,允许用户和生产者同时处理不同的缓冲区。

信号量类型

信号量由操作系统区分成两类:计数信号量二元信号量

1. 计数信号量:信号量 S 的值初始化为系统中资源的数量。每当进程想要访问资源时,它就会在信号量上执行wait()操作,并将信号量值减一。当它释放资源时,它会执行信号量上的signal()操作,并将信号量值加一

当信号量计数变为 0 时,表示进程占用了所有资源。当信号量计数为 0 时,进程需要使用资源。它执行wait()操作并被阻塞,直到信号量值大于 0。

Mutex vs Semaphore

2. 二元信号量:信号量的值在01之间。它类似于互斥锁,但互斥锁是锁定机制,而信号量是信号机制。在二元信号量中,如果进程想要访问资源,它就在信号量上执行wait()操作,并将信号量的值从 1 减为 0。当它释放资源时,它执行signal()操作,并将值增至 1。假设信号量的值为 0,并且进程想要访问资源。在这种情况下,它执行wait()操作并自我阻塞,直到当前使用资源的进程释放资源。

Mutex vs Semaphore

信号量的优点

信号量的一些优点如下:

  • 它允许多个线程访问临界区。
  • 信号量与机器无关。
  • 信号量在微内核的机器无关代码中实现。
  • 它们不允许多个进程进入临界区。
  • 由于信号量存在忙等待,因此从不会浪费进程时间和资源。
  • 它们与机器无关,应该在微内核的机器无关代码中运行。
  • 它们允许灵活地管理资源。

信号量的缺点

信号量也存在一些缺点,例如:

  • 信号量最大的限制之一是优先级反转。
  • 操作系统必须跟踪所有对信号量 wait 和 signal 的调用。
  • 它们的使用从未被强制执行,而仅凭约定。
  • Wait 和 Signal 操作需要按正确的顺序执行,以避免信号量中的死锁。
  • 信号量编程是一种复杂的方法,因此可能无法实现互斥。
  • 对于大规模使用,它也不是一种实用的方法,因为它们的使用会导致模块化丢失。
  • 信号量更容易出现程序员错误
  • ,并且可能由于程序员错误而导致死锁或违反互斥。

互斥锁与信号量的区别

信号量和互斥锁之间的基本区别在于,信号量是信号机制,即进程执行 wait() 和 signal() 操作来指示它们是正在获取还是释放资源。相比之下,互斥锁是锁定机制,如果进程想要获取资源,它必须获取互斥锁对象上的锁。以下是信号量和互斥锁之间的一些更多区别:

Mutex vs Semaphore
条款互斥锁信号量
定义互斥锁是锁定机制,为了获取资源,进程需要锁定互斥锁对象,而在释放资源时,进程必须解锁互斥锁对象。信号量是信号机制,因为在信号量变量上执行的 wait() 和 signal() 操作指示进程是正在获取还是释放资源。
存在形式互斥锁是一个对象。信号量是一个整数变量。
函数互斥锁允许多个程序线程访问单个资源,但不能同时访问。信号量允许多个程序线程访问有限数量的资源实例。
所有权互斥锁对象的锁仅由已获取互斥锁对象锁的进程释放。信号量值可以通过执行 wait() 和 signal() 操作的任何进程在获取或释放资源时进行更改。
分类互斥锁不作进一步分类。信号量可分为计数信号量和二元信号量。
操作互斥锁对象由请求或释放资源的进程锁定或解锁。除了初始化之外,信号量值是使用 wait() 和 signal() 操作修改的。
资源占用如果互斥锁对象已被锁定,则希望获取资源的进程将等待,并由系统排队,直到资源被释放并且互斥锁对象被解锁。假设进程占用了所有资源,并且没有资源可用。在这种情况下,想要获取资源的进程将在信号量变量上执行 wait() 操作并自我阻塞,直到信号量计数大于 0。