【问题标题】:What is the difference between lockless and non-blocking?无锁和非阻塞有什么区别?
【发布时间】:2009-07-28 12:40:58
【问题描述】:

在数据结构同步的上下文中,有人可以澄清“无锁”和“非阻塞”之间的区别吗?这些术语似乎被很多人互换使用,但我还不确定是否在某处隐藏了一些细微的差异。

我的意思是无锁是“没有锁”,非阻塞更像是保证进度。我怀疑一个暗示另一个,但不是相反,我不确定。

欢迎参考。

【问题讨论】:

  • “非阻塞”可能是避免进度风险的最佳方式(甚至可能在内部涉及自旋锁和线程)。每个函数调用都会及时返回或返回部分工作(协同例程 yield、promise 或完成后的回调)。锁定是一种正确性策略,具有正确性风险和进度风险,例如在持有锁时死亡和amdahls-law。另一种非锁定正确性策略和调用交换属性(无锁结构、不可变)的进度策略可能是合适的。

标签: synchronization locking lock-free nonblocking


【解决方案1】:

锁定是一种访问控制机制。我的意思是当您想要独占访问资源时锁定资源。锁门,使用房间/随心所欲,现在为其他人解锁房间,以便他们现在可以使用。当房间被锁住时,没有其他人可以进入房间,因此无法做任何事情。

阻塞用于保证数据检索,除非你没有数据,否则不要回来。继续在门口/管道/插座(基本上任何东西)等待,当数据可用时获取并返回。

加法--
不要被这些单词的字面英文含义所混淆,因为它们都可以在您尝试将它们放入的上下文中互换使用。例如 - locking 就像 阻止其他人使用相同的资源,阻止可以锁定你自己(调用函数)到资源,直到数据可用。

所以 LOCKING 只是意味着您在指定的时间内捕获资源(除非您取消阻止它)。 并且,BLOCKING 是您被阻止,这意味着您无法继续进行,因为您没有数据,继续或继续。

它们的实现方式,通过改变进程的状态,并等待中断或事件发生。

【讨论】:

  • 如果我理解那么锁是阻塞的?
  • @Helltone - 通常一个锁只有在其他人已经在使用它时才会阻塞。
  • 这些 cmets 让我很困惑。所以你说“无锁”是指别人的完成不依赖于自己,“非阻塞”是指自己的完成不依赖于别人。这是你的意思吗?
  • @Helltone -- 没有什么能比得上无锁的了。我再说一遍,说的很清楚,不要按英文的意思去,试着重新思考。
  • 说 lock 只是阻塞更令人困惑,因为你在这里混合了英语和术语。锁定意味着您无法访问资源,除非该资源已从锁定中释放。如果你是锁定资源的人,你可以使用它,如果你不是锁定资源的人,你不能使用它,除非它被锁定资源的人/函数调用释放(CDrom) .阻塞意味着等待数据来自光驱,除非收到数据一直等待,这意味着除非光驱有一张光碟,有一些数据,一直在光驱中寻找光碟
【解决方案2】:

它们完全不同。

锁定意味着您使用某种方法来使用锁定来控制文件访问。这会停止两个进程同时写入同一个文件,当另一个正在读取时停止一个写入,但允许两个进程同时读取。

阻塞意味​​着该方法将等待操作完成后再返回。

更新

响应示例请求...如果有时间,我将尝试添加示例,但现在,这里是对可能性的解释。

我们有 3 种方式来执行锁定:

  • 阻止。如果锁不可用,请等待。
  • 非阻塞。如果锁不可用,则失败。

以及执行 IO 的 2 种方式:

  • 阻止。等待缓冲区准备就绪。
  • 非阻塞。如果我们不能立即读/写,则失败

如果我们正常使用open()read(),我们会得到阻塞IO。如果我们想要非阻塞 IO,我们必须将O_NONBLOCK 标志传递给open(),然后read() 将返回E_AGAIN 而不是阻塞。

默认情况下没有锁定。我们可以用F_SETLKF_SETLKW调用fcntl()来获取锁。如果锁不可用,前者会阻塞,后者会以EACCESEAGAIN 失败。

我认为有两个可能的混淆点:

  • IO 可以是阻塞/非阻塞,锁定可以是阻塞/非阻塞。
  • 除了数据未准备好之外,IO 请求可能会因为另一个进程已锁定文件而阻塞。

【讨论】:

  • 锁定不仅用于文件访问,但我明白你的回答。我不确定它们“完全”不同,也许一个暗示另一个?或者在某些情况下它们是相同的,但不是一般的。那么我的问题是:哪些上下文?。
  • 当然,锁定适用于各种访问——文件访问只是一个简单的例子。它们是正交的问题,你可以有一个没有另一个。
  • @Draemon “你可以有一个没有另一个”。这里真的很受欢迎。
  • 暂无示例,但有解释
【解决方案3】:

是的,无锁意味着没有锁定机制。非阻塞意味着调用将立即返回,而不是等待某些外部事件(例如释放锁或数据到达缓冲区)发生。可以有锁并使用非阻塞调用,例如在调用中

flock(fh, LOCK_SH | LOCK_NB);

这意味着“尝试获得一个读锁,但如果你不能,不要等待一个,立即返回并告诉我你不能”。没有LOCK_NB(“非阻塞”)的LOCK_SH(“共享锁”)的默认行为是等待锁的可用性。

【讨论】:

    【解决方案4】:

    它们可能相似,但经常用于不同的上下文。在数据结构的上下文中,它们将是同一件事。您也可以在 IO 的上下文中使用“非阻塞”,在这种情况下,这意味着函数在返回之前不会等待操作完成,或者操作肯定不会阻塞(例如,读取具有已经被缓存了)。

    此外,非阻塞可能并不意味着某些东西是无锁的。例如,一个数据结构可能使用锁,但有一些不需要锁的非阻塞操作和其他需要锁的阻塞操作。

    【讨论】:

      【解决方案5】:

      通过一个例子试探性的回答:

      考虑一个具有两种方法的对象(称为“事件”),wait()notify()

      • 实施 1:

        notify() 原子地设置一个布尔值。 wait() 循环直到布尔值为真。两者都是无锁,但wait()阻塞

      • 实施 2:

        notify() 获得一个锁,设置一个布尔值然后释放锁。 wait() 获得锁,读取布尔值,释放锁,所有这一切都在一个循环中,直到布尔值为真。因此,两者都是基于锁的阻塞

      • 实施 3:

        最初锁正在使用中。 notify() 检查一个布尔值,如果为真则释放锁。 wait() 获得锁并将布尔值设置为 true。 notify() 非阻塞(是否无锁尚有争议)。 wait() 基于锁阻塞

      所以我会说 non-blocking 意味着 lockless,但它们并不等价,因为 lockless 操作仍然可以阻止某个条件在一个循环中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-28
        • 2012-01-15
        • 1970-01-01
        • 2014-06-24
        • 1970-01-01
        • 2011-09-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多