这个c#类变量需要是可变的吗?
在下面的C代码中,这个c#类变量需要是可变的吗?,c#,multithreading,volatile,C#,Multithreading,Volatile,在下面的C代码中,RunHelper()仅从Run()调用。既然编译器知道它,它会以这样一种方式对它进行优化,即if(terminate)将被if(false)替换吗 当从C#编译到IL时,从RunHelper删除检查的优化不会发生 然而,JIT(从IL编译为机器代码)可能需要RunHelper和Run内部的一个副本来取消调用,然后您担心的优化就可以开始了。不,反射不会阻止这一点,因为您将只看到带有反射的IL,而不会看到机器代码 然而,即使优化没有发生,您也需要担心线程的可见性。如果系统相对频
RunHelper()
仅从Run()
调用。既然编译器知道它,它会以这样一种方式对它进行优化,即if(terminate)
将被if(false)
替换吗
当从C#编译到IL时,从RunHelper
删除检查的优化不会发生
然而,JIT(从IL编译为机器代码)可能需要RunHelper
和Run
内部的一个副本来取消调用,然后您担心的优化就可以开始了。不,反射不会阻止这一点,因为您将只看到带有反射的IL,而不会看到机器代码
然而,即使优化没有发生,您也需要担心线程的可见性。如果系统相对频繁地使用此代码,它将在缓存中保留
terminate
,并且-取决于CPU架构※-其他线程可能不知道对其所做的更改。这就是为什么您应该使用volatile
(或类似的解决方案)
※:在具有单硬件线程(单核,无超线程或类似技术)的计算机上,没有问题。如果有多个硬件线程,它们都有一个缓存,可能有共享缓存,也可能没有共享缓存。在这些情况下,您可能会面临价值变化几乎永远看不见的风险
就我所知,volatile还有其他一些注意事项,它们不会影响您的代码 例如,重新排序不仅仅发生在编译器中,也就是说,CPU可能不会严格按照接收顺序执行机器代码(请参阅)。使用
volatile
会对该重新排序设置约束。但是,读取后仍可以移动写入操作(请参阅:)。您将需要完整的内存屏障来修复它(Interlocked.MemoryBarrier()
在.NET内核中,而Thread.MemoryBarrier()
否则)
当然,还有一个问题。如果你面对它,你将需要interlocated
来解决它,这也意味着你不能使用volatile
,只能使用interlocated
或volatile操作(volatile.Read
/volatile.Write
在.NET内核中或Thread.volatireead
/线程.volatirewrite
否则)要使用该变量,请强制您从bool
更改为int
,因为Interlocked
不能使用bool
另见:
GetBool()
,它总是返回false
,现在尝试terminate=GetBool()
请参见release(优化代码)中是否调用了此方法?是的,它可能必须是易变的,因为您看到的窗口太小,优化几乎肯定会发生。简而言之,您希望在terminate=false之后立即调用KillDummy
在Run
中的code>但在if(terminate)
之前在RunHelper
中触发if语句。这是一个非常小的窗口,大小为RunHelper
的窗口几乎肯定会被内联到Run
,在这种情况下,非易失性变量的缓存几乎肯定会发生。大多数时候,我会直接跳到考虑线程的设计中,例如CancellationToken
或ManualResetEvent
,只需知道它会起作用,而不是胡乱摆弄和考虑挥发物,除非或直到有一个经证实的性能损失,即使用标准内置是其根本原因,并且正在产生明显的影响。
class Dummy
{
private bool terminate;
public Dummy()
{
terminate = false;
}
public void KillDummy() // Called from another thread
{
terminate = true;
}
public void Run()
{
terminate = false;
RunHelper();
}
private void RunHelper() //Only called from Run function
{
if(terminate)
{
Console.WriteLine("Exiting");
}
}
}