这个c#类变量需要是可变的吗?

这个c#类变量需要是可变的吗?,c#,multithreading,volatile,C#,Multithreading,Volatile,在下面的C代码中,RunHelper()仅从Run()调用。既然编译器知道它,它会以这样一种方式对它进行优化,即if(terminate)将被if(false)替换吗 当从C#编译到IL时,从RunHelper删除检查的优化不会发生 然而,JIT(从IL编译为机器代码)可能需要RunHelper和Run内部的一个副本来取消调用,然后您担心的优化就可以开始了。不,反射不会阻止这一点,因为您将只看到带有反射的IL,而不会看到机器代码 然而,即使优化没有发生,您也需要担心线程的可见性。如果系统相对频

在下面的C代码中,
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


另见:


这取决于具体情况。您可以在发布模式下运行它,并使用探查器检查或查看IL代码您使用哪种框架,Core、Mono或.Net framework。您可以做一个简短的活动,让一个方法说
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");
        }
    }
}