此 C# 代码是否会因为寄存器或缓存中的值从未写回主内存而失败?

2024-03-22

在本文中:

http://msdn.microsoft.com/en-us/magazine/jj883956.aspx http://msdn.microsoft.com/en-us/magazine/jj883956.aspx

作者指出,以下代码可能由于“循环读取提升”而失败:

class Test
{
  private bool _flag = true;
  public void Run()
  {
    // Set _flag to false on another thread
    new Thread(() => { _flag = false; }).Start();
    // Poll the _flag field until it is set to false
    while (_flag) ;
    // The loop might never terminate!
  }
}

在循环读取提升中,由于单线程假设,编译器可能会将上面的 while 循环更改为以下内容:

if (_flag) { while (true); }

我想知道的是:如果编译器doesn't执行该优化,由于一个处理器更新寄存器或缓存中的 _flag 并且从不将该缓存刷新回另一个线程可读的内存,循环是否仍然有可能在多处理器计算机上永远运行?我读过“C# 写入是易失性的”,但我链接的文章说这实际上并没有得到 ECMA 规范的保证,而且在 ARM 上也不是这样实现的。我试图弄清楚我必须有多偏执才能编写适用于所有平台的线程代码。

这是一个相关问题:

C# 线程真的可以缓存一个值并忽略其他线程上对该值的更改吗? https://stackoverflow.com/questions/458173/can-a-c-sharp-thread-really-cache-a-value-and-ignore-changes-to-that-value-on-ot

但我认为接受的答案中的代码可能通过循环读取提升进行优化,因此它无法证明内存可见性......


如果编译器不执行该优化,由于一个处理器更新寄存器或缓存中的 _flag 并且从不将该缓存刷新回另一个线程可读的内存,循环是否仍然有可能在多处理器计算机上永远运行?

Yes.

我读过“C# 写入是易失性的”,但我链接的文章说这实际上并没有得到 ECMA 规范的保证,而且在 ARM 上也不是这样实现的。

这有什么关系?主线程不是写,而是读。

我试图弄清楚我必须有多偏执才能编写适用于所有平台的线程代码。

如果他们真的想抓你,那就不是偏执狂。穿线很难。做我所做的:将共享内存的低级操作留给专家。

使用以下代码编写代码最高可能的抽象级别,其中包含专家为您编写的摘要。您几乎不应该按照您所描述的方式编写代码,不是因为它是错误的(尽管它是错误的),而是因为它处于错误的抽象级别。如果你想表达“这个操作可以被取消”的想法,那么使用CancellationToken;这就是他们的目的。如果你想表达“这项工作在未来产生结果”的概念,请使用Task<T>;这就是他们的目的。不要尝试自己推出;让微软为您做这件事。

更新:有关 C# 中的线程安全、易失性语义、低锁技术和为什么你应该避免自己做所有这些事情, see:

Vance 在 2005 年发表了一篇关于低锁技术的精彩文章:

http://msdn.microsoft.com/en-us/magazine/cc163715.aspx http://msdn.microsoft.com/en-us/magazine/cc163715.aspx

我的 2011 年系列三篇文章从这里开始:

http://ericlippert.com/2011/05/26/atomicity-volatility-and-immutability-are- Different-part-one/ http://ericlippert.com/2011/05/26/atomicity-volatility-and-immutability-are-different-part-one/

特别是第三个与您相关,但前两个可能也很有趣。

Joe Duffy 重申了为什么不应该使用 volatile:

http://joeduffyblog.com/2010/12/04/sayon​​ara-volatile/ http://joeduffyblog.com/2010/12/04/sayonara-volatile/

我 2014 年的两篇 Ask The Bug Guys 文章:

http://blog.coverity.com/2014/03/12/can-skip-lock-reading-integer/ http://blog.coverity.com/2014/03/12/can-skip-lock-reading-integer/ http://blog.coverity.com/2014/03/26/reordering-optimizations/ http://blog.coverity.com/2014/03/26/reordering-optimizations/

我已经按照合理的阅读顺序给出了这些内容;如果您发现万斯的文章太难读,请尝试从我的三部分系列文章开始,然后再返回。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

此 C# 代码是否会因为寄存器或缓存中的值从未写回主内存而失败? 的相关文章

随机推荐