当前位置: 首页 > 面试题库 >

自旋锁与信号量

秦珂
2023-03-14
问题内容

信号量和自旋锁之间的基本区别是什么?

什么时候在自旋锁上使用信号灯?


问题答案:

自旋锁和信号灯的主要区别在于四点:

1.他们是什么
一个 自旋锁 是一个可能实现的锁,即一个由忙等待(“旋转”)来实现。信号量是锁的概括(或者相反,锁是信号量的特例)。通常( 但不是必须)
,自旋锁仅在一个进程内有效,而信号量也可用于在不同进程之间进行同步。

锁用于互斥,即 一次一个 线程可以获取该锁并继续执行代码的“关键部分”。通常,这意味着修改一些由多个线程共享的数据的代码。
一个 信号 有一个计数器,并允许自己被收购 一个或多个 线程,这取决于你的价值张贴到它的东西,(在一些实现),这取决于它的最大允许值是什么。

就此而言,可以认为锁是信号量的一种特殊情况,最大值为1。

2.他们的工作
如上所述,自旋锁是一种锁,因此是一种互斥(严格从1到1)的机制。它通常通过原子方式反复查询和/或修改内存位置来工作。这意味着获取自旋锁是“忙碌”的操作,可能长时间(甚至永远!)消耗CPU周期,而实际上却没有实现“空无”。
这种方法的主要诱因是这样一个事实,即上下文切换的开销相当于旋转几百(或数千)次,因此,如果可以通过燃烧几个循环来获得锁,那么总体来说可能是更高效。同样,对于实时应用程序,阻塞并等待调度程序在将来某个遥远的时间返回到它们可能是不可接受的。

相比之下,信号量根本不旋转,或者仅旋转很短的时间(作为避免syscall开销的优化)。如果无法获取信号量,它将阻塞,从而将CPU时间浪费在准备运行的其他线程上。当然,这可能意味着在重新安排线程之前要经过几毫秒,但是如果这没问题(通常不是问题),那么它可能是一种非常有效的,CPU节约的方法

3.它们在出现拥塞时的行为
常见的误解是自旋锁或无锁算法“通常更快”,或者仅对“非常短的任务”有用(理想情况下,不应将同步对象保留更长时间)绝对没有必要)。
一个重要的区别是 存在拥塞时 不同方法的行为。

设计良好的系统通常拥塞少或没有拥塞(这意味着并非所有线程都试图在同一时间获取锁)。例如,通常 不会
编写获取锁的代码,然后从网络加载半兆字节的zip压缩数据,对数据进行解码和解析,最后修改共享的引用(将数据附加到容器等)。释放锁之前。取而代之的是,仅出于访问
共享资源 的目的而获得锁。
由于这意味着在关键部分之外的工作要多于在关键部分内部的工作,因此自然而然地,在关键部分内部的线程的可能性相对较低,因此很少有线程同时争用锁。当然,不时有两个线程会尝试同时获取锁(如果
不可能的 话,您就不需要锁!),但这是一个例外,而不是“健康”系统中的规则。

在这种情况下,自旋锁的性能 大大
优于信号量,因为如果没有锁拥塞,则获取自旋锁的开销仅为十几个周期,而上下文切换则为数百/数千个周期,而丢失则为10-20百万个周期时间片的其余部分。

另一方面,由于拥塞程度很高,或者如果锁被长时间持有(有时您无能为力!),自旋锁将消耗大量的CPU周期,以至于什么也没做。
在这种情况下,信号灯(或互斥锁)是一个更好的选择,因为它允许不同的线程在这段时间内运行 有用的
任务。或者,如果没有其他线程有用,则它允许操作系统降低CPU的速度并减少热量/节约能源。

此外,单核系统上,一个自旋锁会在锁拥塞存在相当低效,作为纺丝线会浪费的状态改变是不可能发生的(直到释放线程调度,其中其完整的时间等待 ISN
等待线程正在运行时 不会发生 !)。因此,在有 任何 争用的情况下,在最佳情况下获取锁大约需要1
1/2个时间片(假设释放线程是正在计划的下一个线程),这不是很好的行为。

4.如何实现
如今,信号量通常会sys_futex在Linux下包装(可选地,自旋锁会在几次尝试后退出)。
自旋锁通常使用原子操作来实现,而不使用操作系统提供的任何操作。在过去,这意味着使用编译器内部函数或非便携式汇编程序指令。同时,C ++
11和C11都将原子操作作为语言的一部分,因此,除了编写可证明正确的无锁代码的一般困难之外,现在有可能在完全可移植且(几乎)可移植的代码中实现无锁代码。无痛的方式。



 类似资料:
  • 队列自旋锁 这是本章节的第二部分,这部分描述 Linux 内核的和我们在本章的第一部分所见到的--自旋锁的同步原语。在这个部分我们将继续学习自旋锁的同步原语。 如果阅读了上一部分的相关内容,你可能记得除了正常自旋锁,Linux 内核还提供自旋锁的一种特殊类型 - 队列自旋锁。 在这个部分我们将尝试理解此概念锁代表的含义。 我们在上一部分已知自旋锁的 API: spin_lock_init - 为给

  • Introduction 这一部分为 linux-insides 这本书开启了新的章节。定时器和时间管理相关的概念在上一个章节已经描述过了。现在是时候继续了。就像你可能从这一部分的标题所了解的那样,本章节将会描述 Linux 内核中的同步原语。 像往常一样,在考虑一些同步相关的事情之前,我们会尝试去概括地了解什么是同步原语。事实上,同步原语是一种软件机制,提供了两个或者多个并行进程或者线程在不同时

  • 主要内容:一、简介,二、Java对象头中的Mark Word,三、偏向锁,四、轻量级锁,五、重量级锁,六、自旋锁,七、锁升级过程一、简介 在讲解这些锁概念之前,我们要明确的是这些锁不等同于Java API中的ReentratLock这种锁,这些锁是概念上的,是JDK1.6中为了对synchronized同步关键字进行优化而产生的的锁机制。这些锁的启动和关闭策略可以通过设定JVM启动参数来设置,当然在一般情况下,使用JVM默认的策略就可以了。 二、Java对象头中的Mark Word HotSpo

  • 我有一个关于管理线程的简单问题。我有3个进程,它们与一个许可证共享相同的信号量。在正常情况下,第一道工序采用该许可证,第二道工序发放两个许可证。第二个过程版本3允许进行第三个过程。我举了一个例子来说明我的问题。 第一个: 第二道工序: } 最后一个: 问题是。当我运行这三个进程并确保进程3是第一个执行的进程时。我会死锁。进程2永远不会打印“Hello 3”,进程1永远不会打印“Hello 2”。为

  • 1“如何确保线程按特定顺序执行”这个问题的答案是正确地使用join()方法(参考:http://beginnersbook.com/2015/03/thread-join-method-in-java-with-example/). 2 15.5中的一个问题在下面的CiCt第6版中按顺序调用。 假设我们有以下代码: “同一个Foo实例将传递给三个不同的线程。线程A将首先调用,线程B将调用第二个,线

  • 信号与槽可以通过使用手写代码显式的实现关联 ,也可以运用 QMetaObject 类规定的槽 函数命名范式来实现自动关联。 10.5.1 显式关联 首先我们来看一下,不使用“自动关联规则”的情形。 在下面这段代码里面,我们定义了一个对话框类,它有一个私有的槽 checkValues(), 它用来检验用户提供的值是否正确。 class ImageDialog : public QDialog, pr