当前位置: 首页 > 编程语言 > C#

允许C#编译器优化局部变量并从内存共享中重新获取值

时间:2023-04-11 00:24:32 C#

允许C#编译器优化局部变量并从内存中重新获取值同步(在这次编辑之前,这一点没有明确表达)。我对C#编译器和JIT编译器执行的优化有疑问。考虑以下简化示例:classExample{privateAction_action;privatevoidInvokeAction(){varlocal=this._action;if(local!=null){local();请忽略示例中的read_action缓存和过期值的可能性,因为没有volatile说明符,也没有任何其他同步。这不是重点:)编译器(或者实际上是运行时的抖动)是否允许优化对局部变量的赋值而不是从内存中读取_action两次:classExample{privateAction_action;privatevoidInvokeAction(){if(this._action!=null){this._action();//可能被其他线程设置为null。}}}当并行分配将字段_action设置为null时,可能会抛出NullReferenceException。当然,这样的“优化”在这个例子中没有意义,因为将值存储在寄存器中并因此使用局部变量会更快。但是在更复杂的情况下,是否可以保证在不重新读取内存中的值的情况下按预期工作?根据ECMA规范中定义的内存模型进行合法优化。如果_action是volatile,内存模型将保证该值只被读取一次,因此不会发生这种优化。但是,我认为当前Microsoft的CLR实现并未优化局部变量。我会(部分地)说与mgronber相反的:-)Aaaah...最后我说了同样的话...只是我引用了一篇文章:-(我会给他+1。这是法律规定的ECMA规范优化,但它是.NET>=2.0“规范”下的非法优化。从Understandingtheimpactoflow-locktechnologyinmultithreadedapplicationsreadhereStrongModel2:.NETFramework2.0Point2:不能引入读写操作。解释如下:但是,该模型不允许引入读,因为这意味着从内存中重新获取值,并且在低锁定代码中,内存可能会发生变化。但请注意同一页上的提示1:避免锁定某些读取在使用ECMA模型的系统中,还有一个额外的微妙之处。即使只将一个内存位置提取到局部变量中,并且多次使用局部,每次使用也可能有不同的值!这是因为ECMA模型允许编译器消除局部变量并在每次使用它们时重新获取位置。如果更新同时发生,则每次提取可能具有不同的值。使用volatile声明可以抑制这种行为,但这个问题很容易被忽视。如果您在Mono下编写,您应该被告知至少在2008年之前它一直在使用ECMA内存模型(或者他们在他们的邮件列表中写道)使用C#7,您应该按如下方式编写您的示例,实际上是IDE会将其建议为“简化”。编译器将生成使用临时局部变量的代码,只有_action可以从主内存中读取_action的位置(无论它是否为null),这有助于防止OP第二个示例中显示的常见竞争,即_Action被访问两次并且可以被中间的另一个线程设置为null。以上是C#学习教程:允许C#编译器优化局部变量并从内存中重新获取共享值。如果对大家有用,需要进一步了解C#学习教程,希望大家多加关注——classExample{privateAction_action;privatevoidInvokeAction(){this._action?.Invoke();}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: