无锁和非阻塞有什么区别?
-
19-09-2019 - |
题
在数据结构同步的背景下,有人可以澄清“无锁”和“非阻塞”之间的区别吗?这些术语似乎被很多人互换使用,但我还不确定是否在某处隐藏着一些微妙的差异。
我的意思是无锁是“没有锁”,而非阻塞更像是保证进度。我怀疑一个暗示另一个,但不是相反,我不确定。
欢迎参考。
解决方案
锁定是一种访问控制机制。我的意思是,当您想要独占访问某个资源时,您会锁定该资源。锁上门,使用房间/做任何你想做的事,现在为其他人解锁房间,以便他们现在可以使用它。当房间被锁上时,其他人无法进入房间,因此无法做任何事情。
阻塞用于保证数据检索,除非您没有数据,否则不会回来。继续在门/管道/插座(基本上是任何东西)处等待,当数据可用时获取并返回。
添加 -
不要对这些单词的字面英语含义感到困惑,因为它们都可以在您尝试放入它们的上下文中互换使用。例如 - 锁定 就好像 阻塞 供其他人使用相同的资源,以及 阻塞 可 锁定 您自己(调用函数)访问资源,直到数据可用。
因此,锁定只是意味着您在指定的时间内捕获资源(除非您取消阻止它)。并且,BLOCKING 是您被阻止,这意味着您无法继续进行,因为您没有数据、继续或继续。
它们的实现方式是通过更改进程的状态并等待中断或事件发生。
其他提示
他们完全不同。
锁定意味着您使用某种方法通过锁来控制文件访问。这会阻止两个进程同时写入同一个文件,在另一个进程正在读取时停止一个写入,但允许两个进程同时读取。
阻塞意味着该方法将等待操作完成后再返回。
更新
为了响应示例请求...如果有时间,我会尝试添加示例,但现在,这里是对可能性的解释。
我们有 3 种方法来执行锁定:
- 没有任何
- 阻塞。如果锁不可用,则等待。
- 非阻塞。如果锁不可用,则失败。
以及2种执行IO的方式:
- 阻塞。等待缓冲区准备就绪。
- 非阻塞。如果我们不能立即读/写则失败
如果我们使用 open()
和 read()
正常情况下,我们会遇到阻塞 IO。如果我们想要非阻塞 IO,我们必须传递 O_NONBLOCK
标记为 open()
, , 和 read()
然后将返回 E_AGAIN
而不是阻塞。
默认情况下没有锁定。我们可以打电话 fcntl()
和 F_SETLK
或者 F_SETLKW
来获取锁。如果锁不可用,前者会阻塞,后者会失败 EACCES
或者 EAGAIN
.
我认为可能有两个容易混淆的地方:
- IO可以是阻塞/非阻塞,锁定可以是阻塞/非阻塞。
- 除了数据未准备好之外,IO 请求还可能因为另一个进程锁定了文件而被阻塞。
是,无锁装置没有锁定机构。非阻塞意味着一个呼叫是否会返回立即而不是等待某些外部事件(例如,锁定的释放,或在缓冲器中的数据到达)发生。这是可能的有锁和使用非阻塞调用,如例如在呼叫
flock(fh, LOCK_SH | LOCK_NB);
这意味着“试图得到一个读锁,但如果你不能,不要四处等待一出,立即返回,并告诉我,你不能”。 LOCK_SH
(“共享锁”),而不LOCK_NB
(“无阻塞”)的默认行为将是等待锁可用性。
它们可以是相似的,但在不同的上下文中经常使用。在数据结构的情况下,他们将同样的事情。你也可以在IO的上下文中使用“非阻塞”为好,在这种情况下,这意味着该功能将不等待操作返回之前或该操作是肯定不会阻止完成(如读取有数据已经被高速缓存)。
另外,无阻塞可能不意味着某事是无锁。例如,一个数据结构可以使用锁,但具有不需要的锁和其它阻塞操作确实需要一个一些非阻塞操作。
通过一个例子初步回答:
考虑一个具有两种方法的对象(称为“事件”), wait()
和 notify()
.
实施1:
notify()
原子地设置一个布尔值。wait()
循环直到布尔值为 true。两者都是 无锁, , 但wait()
是 阻塞.实施2:
notify()
获取锁,设置布尔值,然后释放锁。wait()
获取锁,读取布尔值,释放锁,所有这些都在一个循环中,直到布尔值为真。两者都是如此 基于锁的, 阻塞.实施3:
最初,锁处于使用状态。
notify()
检查一个布尔值,如果为真则释放锁。wait()
获取锁并将布尔值设置为 true。notify()
是 非阻塞 (是否是有争议的 无锁 或不)。wait()
是 基于锁的, 阻塞.
所以我想说 非阻塞 暗示 无锁, ,但它们并不等价,因为 无锁 操作仍然可以因循环中的条件而阻塞。