Lock free 旋转锁是否总是需要内存屏障?在内存屏障上旋转是否昂贵?

Lock free 旋转锁是否总是需要内存屏障?在内存屏障上旋转是否昂贵?,lock-free,spinlock,memory-barriers,barrier,Lock Free,Spinlock,Memory Barriers,Barrier,我写了一些无锁代码,可以在本地 在大多数情况下都是这样 内存读取上的本地旋转是否必然意味着I 旋转前必须始终插入内存屏障 阅读 (为了验证这一点,我制作了一个读写器 这种组合会导致读者永远看不到 书面价值,在某些非常具体的情况下 条件——专用CPU、连接到CPU的进程、, 优化器一路向上运行,没有其他工作在 所以箭头确实指向那个方向,但我不是 完全确定在内存中旋转的成本 屏障。) 如果出现以下情况,通过内存障碍旋转的成本是多少 缓存的存储缓冲区中没有要刷新的内容? i、 例如,所有过程(在C中)

我写了一些无锁代码,可以在本地 在大多数情况下都是这样

内存读取上的本地旋转是否必然意味着I 旋转前必须始终插入内存屏障 阅读

(为了验证这一点,我制作了一个读写器 这种组合会导致读者永远看不到 书面价值,在某些非常具体的情况下 条件——专用CPU、连接到CPU的进程、, 优化器一路向上运行,没有其他工作在 所以箭头确实指向那个方向,但我不是 完全确定在内存中旋转的成本 屏障。)

如果出现以下情况,通过内存障碍旋转的成本是多少 缓存的存储缓冲区中没有要刷新的内容? i、 例如,所有过程(在C中)都是

我认为它是免费的,不会有负担,对吗 内存总线有流量吗

另一种说法是问:记忆障碍能起作用吗 任何超过:刷新存储缓冲区,应用 无效,并防止编译器 跨其位置重新排序读/写操作


正在反汇编时,\uuuu sync\u synchronize()似乎转换为:

lock orl
从英特尔手册(对于新手来说同样模糊):

我的翻译是:“当你说锁,这将是昂贵的,但我们是 只有在必要的时候才这样做。”


@布兰克泽维尔:

我确实测试过,如果写入程序没有明确地从存储缓冲区中推出写入,并且它是在该CPU上运行的唯一进程,那么读取器可能永远看不到写入程序的效果(我可以用一个测试程序来复制它,但正如我前面提到的,它只发生在一个特定的测试中,有特定的编译选项和专用的核心任务——我的算法工作得很好,只有当我对它的工作原理感到好奇并编写了显式测试时,我才意识到它可能会有问题)

我认为默认情况下,简单写操作是WB写操作(回写),这意味着它们不会立即被清除,但读取操作将采用它们的最新值(我认为它们称之为“存储转发”)。因此,我对写操作使用CAS指令。我在《英特尔手册》中发现了所有这些不同类型的写操作(UC、WC、WT、WB、WP),英特尔第3A卷第11-10章,仍在学习

我的不确定性在读者方面:我从McKenney的论文中了解到,还有一个无效队列,一个从总线进入缓存的无效队列。我不确定这部分是如何工作的。特别是,你似乎暗示了通过正常读取进行循环(即,非锁定,无障碍,仅使用volatile确保优化器在编译后离开读取)每次都会检查“无效队列”(如果存在这种情况)。如果简单读取不够好(即,可以读取旧缓存线,该缓存线在排队无效之前仍然有效)(这听起来也有点不连贯,但失效队列是如何工作的?),那么原子读取是必要的,我的问题是:在这种情况下,这会对总线产生任何影响吗?(我想可能不会)


我仍在阅读《英特尔手册》,虽然我看到了关于存储转发的大量讨论,但我还没有找到关于无效队列的好讨论。我决定将我的C代码转换为ASM并进行实验,我认为这是真正了解其工作原理的最佳方法。

我可能还没有完全理解qu估计,但是

如果你在旋转,一个问题是编译器优化你的旋转。Volatile解决了这个问题

内存屏障(如果有)将由写入程序向旋转锁发出,而不是向读卡器发出。写入程序实际上不必使用内存屏障——这样做可以确保写入操作立即被推出,但无论如何,它很快就会退出

屏障阻止线程在其位置上执行代码重新排序,这是它的另一个代价。

指令“xchg reg,[mem]”将通过内核的锁销发出其锁定意图的信号。该信号穿过其他内核并缓存到总线主控总线(PCI变体等)这将完成他们正在做的事情,最终LOCKA(确认)引脚将向CPU发出信号,表示xchg可能完成。然后,锁定信号被关闭。此序列可能需要很长时间(数百个CPU周期或更多)完成。之后,其他核心的相应缓存线将失效,并且您将拥有一个已知状态,即已在核心之间同步的状态

xchg指令是实现原子锁所必需的全部。如果锁本身成功,您可以访问您定义了锁以控制访问的资源。这样的资源可以是内存区域、文件、设备、函数或您拥有的其他资源。不过,程序员始终可以编写使用这些资源的代码当资源被锁定时,此资源不会被锁定。通常,成功锁定后的代码序列应尽可能短,以便其他代码尽可能少地被阻止访问资源

请记住,如果锁定不成功,您需要通过发出新的xchg重试


“无锁”是一个吸引人的概念,但它需要消除共享资源。如果应用程序有两个或多个内核同时读取和写入公共内存地址,“无锁”不是一个选项。

请记住,屏障通常用于排序内存访问集,因此您的代码很可能在其他位置也需要屏障。例如,屏障要求看起来像这样并不少见:

while ( 1 ) {

    v = pShared->value;
    __acquire_barrier() ;

    if ( v != 0 ) {
        foo( pShared->something ) ;
    }
}
此屏障将阻止在if块中加载和存储(即:
pShared->something)Volume 3A: System Programming Guide, Part 1 --   8.1.2

Bus Locking

Intel 64 and IA-32 processors provide a LOCK# signal that
is asserted automatically during certain critical memory
operations to lock the system bus or equivalent link.
While this output signal is asserted, requests from other
processors or bus agents for control of the bus are
blocked.

[...]

For the P6 and more recent processor families, if the
memory area being accessed is cached internally in the
processor, the LOCK# signal is generally not asserted;
instead, locking is only applied to the processor’s caches
(see Section 8.1.4, “Effects of a LOCK Operation on
Internal Processor Caches”).
while ( 1 ) {

    v = pShared->value;
    __acquire_barrier() ;

    if ( v != 0 ) {
        foo( pShared->something ) ;
    }
}
pShared->something = 1 ;  // was 0
__release_barrier() ;
pShared->value = 1 ;  // was 0