对无锁编程的一些疑问

Some doubts on lock free programming

本文关键字:编程      更新时间:2023-10-16

嗨,伙计们,
首先对不起,这将是一个中等长的帖子。所以,请耐心通读。

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

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

任务1> 在 while 循环上旋转如何比在
互斥锁上阻塞更有效?
Quest2> 使用互斥锁的良好设计还可以确保系统的进步,那么
根据定义,这不是无块吗?

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

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

任务3> 那么,无锁不是像旋转锁这样的东西吗?如果是,为什么我们不能使用 
pthread 旋转锁 ?

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

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

提前谢谢。

这是很多问题!

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

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

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

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

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

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

上面汇编中的":memory"是否意味着内存屏蔽?如果是,这不需要大约 100 个周期才能实现吗?

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

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

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

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

  2. 如果我没记错的话,"内存"意味着不要将内存变量优化为寄存器变量。不太对劲。准确地说,它告诉编译器必须对内存的使用进行强排序。但它与硬件内存屏蔽无关。

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