0

大家好,
首先很抱歉,这将是一个中等长度的帖子。所以,请耐心阅读。

在这里,我将记录一些我在浏览一些关于无锁编程的文章时学到的概念,并提出我对这种学习的疑问。
此外,讨论是在 *NIX 多处理器平台上进行的。

首先说“LOCKLESS = BLOCKLESS”,因为据说线程系统作为一个整体取得了进展,因为 CAS/DCAS 只有在某个线程取得进展时才会失败。
因此,我们可以说,在这里,如果在互斥锁上阻塞,我们正在旋转/等待一个条件(例如,CAS while 循环)。

Quest1 > 如何在 while 循环上旋转比在
互斥锁上阻塞更有效?
Quest2 > 使用互斥锁的良好设计还可以确保系统继续运行,那么
根据定义,BLOCKLESS 不也是吗?

作为对问题 1 的回答,有人会争辩说阻塞可能会进入内核等待状态,并且可能存在代价高昂的上下文切换。任何进一步的澄清将不胜感激。

好的,假设在得到前 2 个问题的答案后,我会确信当要完成的原子操作不是很大/耗时时,无锁是非常快速和实时的。

Quest3 > 那么,无锁是不是类似于 spinlock ?如果是,为什么我们不能使用
pthread 自旋锁?

展望未来,在网上的大多数文献中,人们会看到这样的原子操作实现:

__asm__ __volatile__("lock\nxadd" X " %0,%1"                                               
                          : "=r"(结果),"=m"(*(T *)i_pAddress)                                            
                          :“0”(i_addValue)                                                              
                          : “记忆”); // 这是什么意思 ?记忆栅栏?
Quest4 > 上述汇编中的 ":memory" 是否意味着内存围栏?如果是,
那不需要大约 100 个周期来实施吗?
Quest5 > 这里的lock指令是不是断言操作是
在共享资源上进行的,所以其他线程在这里阻塞了?
据我所知,
这个问题对于或多或少最近的英特尔多进程架构无效,
因为锁定是在缓存行上完成的。

提前致谢。

4

2 回答 2

2
  1. 无锁确实以某种方式使用了一些类似自旋锁的东西。但是当我们将自旋称为锁时,我们通常希望同步大块代码。当我们谈论无锁时,它针对一项任务,通常只有一条指令。第一个在做长的事情时旋转,第二个在做短的事情时旋转。第一个继续旋转,第二个“旋转”只是“重试”。

  2. 如果我没记错的话,“内存”的意思是不要将内存变量优化为寄存器变量。(不太正确。准确地说,它告诉编译器内存的使用必须是强排序的。但它与硬件内存无关击剑。)

  3. 锁定指令不如非锁定指令快,但仍比上下文切换快。但它比较慢,所以通常在写一个旋转的东西时,我们会先做一个非锁测试。如果它通过了,我们将进行锁定。

于 2012-05-03T06:59:16.477 回答
2

这是很多问题!

在 while 循环上旋转如何比在互斥锁上阻塞更有效?

如果资源基本上没有争用,平均而言,您不必长时间旋转。这可能比使用互斥锁更便宜。

使用互斥锁的良好设计还可以确保系统的进展,那么根据定义,这不是 BLOCKLESS 吗?

这对等待的线程可能更公平。如果在等待资源时旋转,“不幸”的线程可能需要等待很长时间。

那么,无锁不是像 spinlock 这样的东西吗?如果是,为什么我们不能使用 pthread 自旋锁?

如果您对如何使算法无锁有一个好主意,那么您可能根本不需要旋转。

上述汇编中的 ":memory" 是否意味着内存围栏?如果是,那不是需要大约 100 个周期来实现吗?

是的,这是需要它的系统上的内存防护。同步大量 CPU 缓存需要很长时间(可能超过 100 个时钟)。另一方面,自旋锁或互斥锁也需要内存栅栏才能正常工作。

这里的lock指令不是断言操作是在共享资源上完成的,因此其他线程在这里阻塞了吗?

这是一种不同类型的阻塞,可能在硬件级别。如果其他线程需要您刚刚更新的数据,他们将需要等待它在他们的CPU 上可用。

于 2012-05-03T06:59:56.920 回答