2009-12-18 82 views
3

我不明白为什么在这个实现stopped不是volatile - 如果一个不同的线程更新它会正确地反映?优雅地关闭工作线程

其次是测试(!Stopping)原子?

​​

编辑

此代码是从an article written by Jon Skeet

+2

我不明白,Jon Skeet如何描述这一点? – YOU 2009-12-18 12:13:56

+0

@ S.Mark:它来自Jon Skeets关于关闭工作线程的页面。 – 2009-12-18 12:20:25

+2

@ S.Mark ...与编程有关的任何东西都与Jon Skeet有关......这应该是Jon Skeet的事实!http://meta.stackexchange.com/questions/9134/jon-skeet-facts – James 2009-12-18 12:55:38

回答

6

因为它只能在lock内访问。 A lock行为,以确保您看到最新的值。

重新原子性(和我假设你真的意思是在这里同步?);它没有任何可能;即使Stopping已同步,但我们不能再相信该值是我们退出lock后的最新值。因此,!StoppingStopping没有更多或更少的同步。重要的是我们知道我们最近至少检查过了。有一个边缘情况下,我们检查之后我们检查标志,但这很好:当我们检查时,确实应该继续。

+0

我明白了吗? 每次获得锁定寄存器都会被刷新并且永远不会读取陈旧值?换句话说,如果我在一个紧密的循环中获得一个锁,那么我不需要易失性?自从? – 2009-12-18 17:07:07

+0

只要所有**其他**线程只有在它们持有(相同)锁定时才更新字段,那么是的。如果其他线程在没有获得锁的情况下更新字段*,则所有投注都将关闭。 – 2009-12-18 18:46:20

1

请参阅this entry on SO。它解释了为什么锁定比volatile更受欢迎。此代码的

+0

但是,这个例子不属于链接条目中的“什么是非常好的”类别吗?没有办法设置停止或停止为假,所以不会有任何竞争条件。 – Niki 2009-12-18 12:59:12

2

行为是在C#语言规范的第3.10节中定义:

C#程序前进的执行,使得每个执行线程的副作用是在临界执行点保存。副作用定义为读取或写入易失性字段,写入非易失性变量,写入外部资源以及抛出异常。必须保留这些副作用顺序的关键执行点是对易失性字段(第10.5.3节),锁定语句(第8.12节)以及线程创建和终止的引用。

换句话说,锁定语句足以保证避免需要声明停止的字段volatile。

JIT编译器如何实现此规则是一个有趣的问题,因为锁定语句仅调用Monitor.Enter()和Exit()方法。我不认为它对这些方法有特别的了解,我认为这是进入在Enter()调用之后开始的try块的副作用。但这只是一个猜测。