这是对 Thread.MemoryBarrier() 的正确使用吗?
不。假设一个线程在循环开始执行之前设置了标志。循环仍然可以使用标志的缓存值执行一次。那是正确的吗?这对我来说肯定是不正确的。我希望如果我在第一次执行循环之前设置标志,循环执行零次,而不是一次。
据我了解 Thread.MemoryBarrier(),在 while 循环中进行此调用将阻止我的工作线程获取 shouldRun 的缓存版本,并有效地防止发生无限循环。我对 Thread.MemoryBarrier 的理解是否正确?
内存屏障将确保处理器不会对读取和写入进行任何重新排序,以便实际观察到逻辑上在屏障之前的内存访问在它之后,反之亦然。
如果你下定决心要做低锁代码,我会倾向于使该字段易失,而不是引入显式的内存屏障。“volatile”是C# 语言的一个特性。一个危险且难以理解的特性,但却是该语言的一个特性。它清楚地向代码的读者传达了所讨论的字段将在多个线程上不加锁的情况下使用。
这是确保一旦任何线程将 shouldRun 设置为 false 后我的循环将停止的合理方法吗?
有些人会认为这是合理的。如果没有非常非常好的理由,我不会在我自己的代码中这样做。
通常,低锁定技术是出于性能考虑而证明的。有两个这样的考虑:
首先,竞争锁可能非常慢;只要锁中有代码在执行,它就会阻塞。如果您因为争用太多而遇到性能问题,那么我会首先尝试通过消除争用来解决问题。只有当我无法消除争用时,我才会采用低锁定技术。
其次,可能是非竞争锁太慢了。如果您在循环中执行的“工作”花费的时间少于 200 纳秒,那么检查无争用锁所需的时间(大约 20 ns)是工作时间的很大一部分。在这种情况下,我建议您在每个循环中做更多的工作。真的有必要在设置控制标志后的 200 ns 内停止循环吗?
只有在最极端的性能场景中,我才能想象检查非竞争锁的成本是程序所花费时间的很大一部分。
而且,当然,如果你每 200 ns 左右就引入一个内存屏障,你也可能以其他方式破坏性能。处理器希望为您进行那些移动内存访问的实时优化;如果你强迫它不断地放弃这些优化,你就错失了潜在的胜利。