java规范17.3睡眠和产量
重要的是要注意 Thread.sleep和Thread.yield都没有任何同步语义。特别是,编译器不必在调用Thread.sleep或Thread.yield之前将寄存器中缓存的写入刷新到共享内存,编译器也不必在调用Thread.sleep或Thread后重新加载缓存在寄存器中的值。产量
例如,在下面(损坏的)代码片段中,假设this.done是一个非易失性布尔字段:
while (!this.done) Thread.sleep(1000);
编译器可以自由地读取this.done字段一次,并在循环的每次执行中重用缓存值。这意味着循环永远不会终止,即使另一个线程改变了this.done的值。
问题:在C#中是否相同?
我们知道,我们可以添加Thread.MemoryBarrier();解决问题。
while(this.done)
{
Thread.MemoryBarrier();
Thread.sleep(1000);
}
问题:但是在下列情况下编译器是否能够将fun()识别为MemoryBarrier?
public static void fun()
{
Thread.MemoryBarrier();
}
while(this.done)
{
fun();
Thread.sleep(1000);
}
如果没问题,为什么它不能将睡眠识别为MemoryBarrier,因为它无法确定睡眠是否包含MemoryBarrier?
答案 0 :(得分:1)
由于Sleep
没有明确声称拥有任何此类语义,唯一安全的答案是“不要依赖它具有任何此类语义”#34;。有很多方法可以安全地轮询变量或检查其他一些令牌(我个人很想看Monitor.Wait(obj, timeout)
,但YMMV)。你说:
我认为睡眠和其他功能应该被识别为MemoryBarrier。
由于Sleep
方法并未声明要执行此操作,因此您无法依赖它。可能是设计师积极地反对你;可能它甚至从未进行过讨论(毕竟,这是一种相当随意的效果)。