c# - 此 C# 代码是否会因为寄存器或缓存中的值永远不会写回主内存而失败?

标签 c# multithreading caching

在本文中:

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); }

我想知道的是:如果编译器执行该优化,那么由于一个处理器在注册或缓存并且从不将该缓存刷新回另一个线程可读的内存?我读过“C# 写入是易变的”,但我链接到的文章说这实际上并没有得到 ECMA 规范的保证,而且在 ARM 上也没有以这种方式实现。我试图弄清楚我必须多么偏执才能编写适用于所有平台的线程代码。

这是一个相关的问题:

Can a C# thread really cache a value and ignore changes to that value on other threads?

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

最佳答案

if the compiler doesn't perform that optimization, is there still potential for the loop to run forever on a multiprocessor machine due to one processor updating _flag in a register or cache and never flushing that cache back to memory readable by the other thread?

是的。

I've read that "C# writes are volatile," but the article I linked to says this is not actually guaranteed by the ECMA spec and things aren't implemented that way on ARM.

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

I'm trying to figure out how paranoid I have to be to write threaded code that will work on all platforms.

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

使用尽可能高的抽象级别编写您的代码,并由专家为您编写抽象。您几乎不应该按照您描述的那样编写代码,不是因为它是错误的——尽管它是错误的——而是因为它处于错误的抽象级别。如果您想表示“可以取消此操作”的想法,请使用 CancellationToken ;这就是他们的目的。如果你想表示“这项工作在未来产生结果”的概念,请使用 Task<T> ;这就是他们的目的。不要尝试自己动手;让 Microsoft 为您完成。

更新:有关 C# 中的线程安全、可变语义、低锁技术以及为什么应该避免自己做所有这些事情的更多信息,请参阅:

万斯 2005 年关于低锁技术的精彩文章:

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

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

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

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

Joe Duffy 重申了为什么不应该使用 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/26/reordering-optimizations/

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

关于c# - 此 C# 代码是否会因为寄存器或缓存中的值永远不会写回主内存而失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23110762/

相关文章:

c++ - 惰性初始化缓存...如何使其成为线程安全的?

multithreading - 如何在 Outlook 2007 加载项中高效运行后台任务?

javascript - CacheStorage - 如何检索请求的缓存时间

c# - 具有许多可选参数的过滤器不起作用

c# - 在 C# 中,是否可以在不使用运算符的情况下评估变量是否不同于 null?

javascript - 选择 EditorFor MVC C# View 上的所有复选框

python - 为什么在 Python 3 中未编译的、重复使用的正则表达式要慢得多?

c# - 如何在 C#.net 中使用 awesomium 登录谷歌帐户?

c - 多线程程序中的段错误

访问全局管理结构中的结构数组时的linux共享内存错误