引用赋值是primefaces,所以为什么Interlocked.Exchange(ref Object,Object)需要?

在我的multithreadingasmx Web服务中,我有一个我自己types的SystemData的类字段_allData,它由less数List<T>Dictionary<T>标记为volatile 。 系统数据( _allData )刷新一次,我通过创build另一个名为newData对象,并用新的数据填充它的数据结构。 完成后,我只是分配

 private static volatile SystemData _allData public static bool LoadAllSystemData() { SystemData newData = new SystemData(); /* fill newData with up-to-date data*/ ... _allData = newData. } 

这应该工作,因为赋值是primefaces的,并且对旧数据的引用的线程继续使用它,其余的在赋值之后有新的系统数据。 然而,我的同事说,而不是使用volatile关键字和简单的assigment,我应该使用InterLocked.Exchange因为他说,在某些平台上,不能保证参考分配是primefaces。 而且:当我声明the _allData字段为volatile

 Interlocked.Exchange<SystemData>(ref _allData, newData); 

产生警告“对易失性字段的引用不会被视为易失性”我应该怎么看待这个问题?

这里有很多问题。 一次考虑一个:

引用赋值是primefaces,所以为什么Interlocked.Exchange(ref Object,Object)需要?

参考分配是primefaces的。 Interlocked.Exchange不会仅执行引用分配。 它读取一个variables的当前值,存储旧值,并将新值赋给variables,全部作为一个primefaces操作。

我的同事说,在一些平台上,不能保证参考分配是primefaces的。 我的同事是对的吗?

不可以。所有.NET平台上的引用赋值都是primefaces的。

我的同事是从错误的前提推理的。 这是否意味着他们的结论是不正确的?

不必要。 你的同事可能会给你很好的build议,原因很糟糕。 也许还有一些其他的原因,你应该使用Interlocked.Exchange。 无锁编程是非常困难的,当你离开这个领域的专家所熟知的行之有效的做法时,你就会脱离杂草,冒着最恶劣的竞争条件冒险。 我既不是这个领域的专家,也不是你的代码的专家,所以我不能以这样或那样的方式做出判断。

产生警告“对易失性字段的引用不会被视为易失性”我应该怎么看待这个问题?

你应该明白为什么这是一个普遍的问题。 这将导致理解为什么警告在这个特殊情况下是不重要的。

编译器给出这个警告的原因是因为将一个字段标记为volatile意味着“该字段将在多个线程上更新 – 不会生成任何代码来caching该字段的值,并确保任何读取或写入这个字段并不是“通过处理器caching不一致”而是“及时向前和向后移动”。

(我假设你已经理解了所有这些,如果你对volatile的含义没有详细的理解,以及它如何影响处理器caching语义,那么你就不知道它是如何工作的,不应该使用volatile。是很难得到正确的;确保你的程序是正确的,因为你了解它是如何工作的,而不是偶然的。)

现在假设你通过传递一个ref到这个字段来创build一个variables,它是一个volatile字段的别名。 在被调用的方法中,编译器没有任何理由知道引用需要具有易失性语义! 编译器会高兴地为无法实现易失性字段规则的方法生成代码,但该variables一个易失性字段。 这可以完全破坏你的无锁逻辑; 总是假设易失性字段总是以易失性语义访问。 把它看作是有时而不是其他时候是不稳定的, 你必须始终保持一致,否则你不能保证其他访问的一致性。

因此,当你这样做的时候,编译器会发出警告,因为它可能会彻底搞乱你精心开发的无锁逻辑。

当然,Interlocked.Exchange 为了期望一个易变的领域而写的,并且做正确的事情。 这个警告因此是误导性的。 我非常后悔, 我们应该做的是实现一些机制,像Interlocked.Exchange这样的方法的作者可以把一个属性放在方法上说:“这个方法需要一个引用强制variables的volatile语义,所以压制警告”。 也许在未来版本的编译器中,我们应该这样做。

要么你的同事是错误的,要么他知道C#语言规范没有的东西。

5.5variables引用的primefaces性 :

“读取和写入以下数据types是primefaces的:bool,char,byte,sbyte,short,ushort,uint,int,float和referencetypes。

因此,您可以写入易失性参考,而不会有损坏值的风险。

当然,您应该小心如何确定哪个线程应该获取新的数据,从而最大限度地减less一次有多个线程执行此操作的风险。

Interlocked.Exchange <T>

将指定typesT的variables设置为指定值,并返回原始值,作为primefaces操作。

它改变并返回原始值,因为你只是想改变它而没用,正如Guffa所说,它已经是primefaces的了。

除非一个profiler被certificate是应用程序中的一个瓶颈,否则你应该考虑解锁,这样更容易理解并certificate你的代码是正确的。

Iterlocked.Exchange()不仅仅是primefaces的,它还处理内存可见性:

以下同步function使用适当的屏障来确保内存sorting:

进入或离开关键部分的function

信号同步对象的函数

等待function

互锁function

同步和多处理器问题

这意味着,除了primefaces性,它确保:

  • 对于调用它的线程:
    • 没有对指令进行重新sorting(通过编译器,运行时或硬件)。
  • 对于所有主题:
    • 在这条指令之前没有对内存进行读操作会看到这条指令的改变。
    • 这条指令之后的所有读操作都将看到这条指令所做的更改。
    • 在指令更改到达主存储器之后,所有写入存储器的指令都会发生(当完成时将该指令更改到主存储器,而不让硬件刷新它自己的开启定时)。
Interesting Posts