自旋锁与互斥锁的区别
mutex
是使用系统中任何资源的钥匙。如果拥有mutex
,就可以使用资源。如果mutex
没有被释放,则进程进入该特定资源的等待队列中。
spin-lock
是一种机制,在这种机制中,需要资源的进程,轮询资源上的锁直到得到它。也称为忙等待。进程将在循环中忙碌,直到获得资源。
第一个区别:即等待资源锁的方式。在mutex
的情况下,进程进入等待状态,并且不使用CPU。在spin-lock
中,进程继续循环,因此即使在等待时也使用处理器。
第二个区别:什么时候使用自旋锁还是使用互斥锁。
当一段代码无法进入睡眠状态时,最好使用自旋锁。中断请求处理程序应该使用自旋锁。
互斥锁适用于用户空间程序,其中进程的睡眠不会影响系统。
当我们有多处理器系统或者使用了抢占式的单处理器系统时,自旋锁是有意义的。在没有使用抢占的单处理器系统中使用自旋锁可能会导致进程永远自旋的死锁。
标准 | 互斥锁 | 自旋锁 |
---|---|---|
机制 | 测试锁,如果可用,使用资源;如果不可用,进入等待队列。 | 测试锁,如果可用,使用资源,如果不可用,再次循环并测试锁,直到获得锁。 |
什么时候使用 | 进程需要花费相当长的时间来获得锁。 用户空间程序。 | 当进程不会进入睡眠状态时使用。 在相当短的等待时间内使用。 |
缺点 | 产生进程上下文切换和调度成本 | 处理器始终处于忙等状态,直到获得锁,浪费了CPU周期。 |
信号量和互斥锁的区别
什么是信号量
信号量只是一个非负的变量,在线程之间共享。信号量是一种信号机制,等待信号量的线程可以由另一个线程发出信号。它使用两个原子操作:(1)wait
(2)signal
用于进程同步。
什么是互斥锁
mutex
的完整形式是互斥对象。它是一种特殊类型的二元信号量,用于控制对共享资源的访问。它包括一个优先级继承机制,以避免扩展的优先级反转问题。它允许当前较高优先级的任务在尽可能短的时间内保持阻塞状态。然而,优先级继承并不能纠正优先级反转问题,只是将其影响最小化。
主要区别
mutex
是一种锁机制,而semaphore
是一种信号机制。mutex
是一个对象,而semaphore
是一个整数。mutex
没有子类型,而semaphore
有两种类型,分别是计数信号量和二元信号量。semaphore
支持signal
和wait
操作,而mutex
只能被请求或释放资源的进程修改。
参数 | 信号量 | 互斥锁 |
---|---|---|
机制 | 信号机制 | 锁机制 |
数据类型 | 信号量是一个整型变量 | mutex 是一个对象 |
更改操作 | wait() 和signal() | mutex 只能由请求或释放资源的进程更改。 |
资源管理 | 如果没有资源是空闲的,进程需要执行wait() 操作,应该等到信号量的计数大于0。 | 如果mutex 被锁定,则该进程必须等待。进程保持在队列中,只有当mutex 被解锁时才可以访问。 |
线程 | 可以有多个线程程序 | 多个线程不能同时拥有mutex |
所有权 | 任何释放或获取资源的进程都可以更改信号量 | mutex 只能由获得它的进程释放 |
类型 | 计数信号量,二元信号量 | 没有子类型 |
操作 | wait() 和signal() | locked 和unlocked() |
资源占用 | 如果所有资源都被占用,并且请求资源的进程执行wait() 操作阻塞自己,直到信号量大于1为止。 | 如果mutex 被锁定,则请求资源的进程在释放mutex 之前等待并由系统排队 |
- 只有一项任务可以获得
mutex
。因此,存在与mutex
相关联的所有权,并且只有所有者才能释放mutex
。 mutex
不是二元信号量。
生产者-消费者问题
考虑标准的生产者—消费者问题,假设我们有一个4096字节长度的缓冲区。生产者线程收集数据并将其写入缓冲区。消费者线程处理从缓冲区收集的数据。目标是,两个线程不应同时运行。
使用mutex
互斥锁提供互斥,生产者和消费者都可以拥有互斥锁并继续它们的工作,只要缓冲区被生产者填满,消费者就需要等待,反之亦然。
在任何时候,只有一个线程可以处理整个缓冲区。
使用信号量
可以将4KB缓冲区拆分成4个1KB的缓冲区(相同的资源)。一个信号量可以与这四个缓冲区相关联。消费者和生产者可以同时在不同的缓冲区上工作。
信号量的优点
- 允许多个线程访问临界区。
- 与机器无关。
- 信号量在微内核的机器无关代码中实现。
- 信号量不允许多个进程进入临界区。
mutex的优点
mutex
只是在进入临界区之前获得,退出临界区之后释放的一个简单锁。- 在任何时间内只能有一个线程处于临界区,因此不存在竞争条件,且数据始终保持一致。
信号量的缺点
- 信号量最大的限制之一是优先级反转问题。
- 操作系统必须跟踪所有对
wait()
和signal()
的调用。 - 为了避免信号量中的死锁,
wait()
和signal()
需要以正确的顺序执行。
mutex的缺点
- 临界区中只能允许有一个线程。
- 可能会导致忙等待状态,浪费CPU时间。
- 它不能从获取它的上下文不同的上下文中锁定或解锁。
- 如果一个线程获得锁并进入睡眠状态或被抢占,则另一个线程可能无法继续前进,这可能导致饥饿问题。