互斥锁是不是保证线程将始终将更新的值存储到主内存中?

Posted

技术标签:

【中文标题】互斥锁是不是保证线程将始终将更新的值存储到主内存中?【英文标题】:Does a mutex lock guarantee that a thread will always store updated values into the main memory?互斥锁是否保证线程将始终将更新的值存储到主内存中? 【发布时间】:2021-12-31 11:17:06 【问题描述】:

一个。使用互斥锁访问内存位置是否意味着无论关键代码对互斥变量所做的任何事情都将最终进入主内存,而不仅仅是在线程的缓存或寄存器中更新而没有主内存中值的新副本?

b.如果是这样的话,我们是不是像没有缓存一样有效地运行关键核心(至少没有互斥锁变量的缓存位置)?

c。如果是这种情况,那么关键代码是否不是重量级代码,并且需要尽可能小,考虑到至少在互斥锁的开头和结尾需要继续读取和写入主内存- 锁定会话?

【问题讨论】:

【参考方案1】:

一个。使用互斥锁访问内存位置是否意味着关键代码对互斥变量所做的任何事情都将最终进入主内存,而不仅仅是在线程的缓存或寄存器中更新,而没有主内存中值的新副本?

正确实现的互斥锁可确保在互斥锁释放时其他代理(例如其他 CPU)可以看到先前的写入。在具有缓存一致性(例如 80x86)的系统上,修改在缓存中时可见,并且修改是否到达主内存并不重要。

本质上(过度简化),为了缓存一致性,当另一个 CPU 想要修改的数据时,它会广播一个请求(比如“嘿,我想要地址 123456 的数据”),如果它在另一个 CPU 的缓存中其他 CPU 响应“这是您想要的数据”,如果数据不在任何缓存中,则内存控制器响应“这是您想要的数据”;并且 CPU 获取最新版本的数据,无论数据在哪里或对请求的响应如何。在实践中它要复杂得多——如果你有兴趣,我建议阅读 MESI 缓存控制协议 (https://en.wikipedia.org/wiki/MESI_protocol)。

b.如果是这样的话,我们是不是像没有缓存一样有效地运行关键核心(至少没有互斥锁变量的缓存位置)?

如果是这种情况(例如,如果没有缓存一致性);某些东西(释放互斥锁的代码)必须确保在其他东西可以获取互斥锁之前将修改后的数据写回RAM。这并不妨碍缓存在临界区内部使用(例如临界区可以写入缓存,然后修改后的数据可以从缓存发送到 RAM)。

成本取决于各种因素(CPU 速度、缓存速度和内存速度,以及缓存是“回写”还是“直写”,以及修改了多少数据)。在某些情况下(带有直写缓存的 CPU 相对较慢),成本可能几乎为零。

c。如果是这种情况,那么关键代码是否不是重量级代码,并且需要尽可能小,考虑到至少在互斥锁的开头和结尾需要继续读取和写入主内存- 锁定会话?

它没有不使用缓存那么重。

同步访问(不管它是如何完成的)总是比不同步访问更昂贵(并且因为所有数据都被弄乱而崩溃)。 ;-)

多线程代码的挑战之一是在同步成本和并行性之间找到一个很好的折衷 - 少量锁(或单个全局锁)降低了同步成本但限制了并行性(线程什么都不做等待获取锁);并且大量的锁会增加同步的成本(例如,获取更多的锁比获取一个更昂贵)但允许更多的并行性。

当然,并行性也受到 CPU 数量的限制;这意味着对一个系统(CPU 很少)的良好折衷可能不是对另一个系统(CPU 很多)的良好折衷。

【讨论】:

很好的答案,感谢您花时间写下来。

以上是关于互斥锁是不是保证线程将始终将更新的值存储到主内存中?的主要内容,如果未能解决你的问题,请参考以下文章

Unix网络编程-同步

如果只有一个线程使用互斥锁,跨线程的共享内存会损坏吗?

互斥锁

iOS汇编教程ARM Exclusive - 互斥锁与读写一致性的底层实现原理

锁的内存语义

线程间通信都有哪些方式