3

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

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

欢迎参考。

4

5 回答 5

6

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

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

加法
——不要被单词的字面英文意思混淆,因为它们都可以在你尝试放入它们的上下文中互换使用。例如——锁定就像阻止其他人使用它们一样资源,并且阻塞可以将自己(调用函数)锁定到资源,直到数据可用。

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

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

于 2009-07-28T12:51:26.203 回答
3

他们完全不同。

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

阻塞意味着该方法将在返回之前等待操作完成。

更新

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

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

  • 没有任何
  • 阻塞。如果锁不可用,请等待。
  • 非阻塞。如果锁不可用,则失败。

以及 2 种执行 IO 的方法:

  • 阻塞。等到缓冲区准备好。
  • 非阻塞。如果我们不能立即读/写失败

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

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

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

  • IO可以是阻塞/非阻塞,锁定可以是阻塞/非阻塞。
  • 除了数据未准备好之外,IO 请求可能会因为另一个进程锁定文件而阻塞。
于 2009-07-28T12:46:12.723 回答
1

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

flock(fh, LOCK_SH | LOCK_NB);

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

于 2009-07-28T12:45:17.123 回答
1

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

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

于 2009-07-28T12:49:37.310 回答
0

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

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

  • 实施1:

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

  • 实施2:

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

  • 实施3:

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

所以我会说非阻塞意味着无锁,但它们并不等价,因为无锁操作仍然可以阻塞循环中的条件。

于 2009-07-28T14:53:03.917 回答