引用分配是原子的,为什么需要 Interlocked.Exchange(ref Object, Object) ? [英] reference assignment is atomic so why is Interlocked.Exchange(ref Object, Object) needed?

查看:25
本文介绍了引用分配是原子的,为什么需要 Interlocked.Exchange(ref Object, Object) ?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的多线程 asmx Web 服务中,我有一个属于我自己类型 SystemData 的类字段 _allData,它由几个标记为 ListDictionary 组成代码>易失性.系统数据 (_allData) 会不时刷新,我通过创建另一个名为 newData 的对象并用新数据填充它的数据结构来实现.完成后我只分配

In my multithreaded asmx web service I had a class field _allData of my own type SystemData which consists of few List<T> and Dictionary<T> marked as volatile. The system data (_allData) is refreshed once in a while and I do it by creating another object called newData and fill it's data structures with new data. When it's done I just assign

private static volatile SystemData _allData

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

这应该可以工作,因为分配是原子的,并且引用旧数据的线程继续使用它,其余的线程在分配后立即拥有新的系统数据.但是我的同事说我应该使用 InterLocked.Exchange 而不是使用 volatile 关键字和简单的赋值,因为他说在某些平台上不能保证引用赋值是原子的.此外:当我将 _allData 字段声明为 volatile 时,

This should work since the assignment is atomic and the threads that have the reference to old data keep using it and the rest have the new system data just after assignment. However my collegue said that instead of using volatile keyword and simple assigment I should use InterLocked.Exchange because he said that on some platforms it's not guaranteed that reference assignment is atomic. Moreover: when I declare the _allData field as volatile the

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

产生警告对易失性字段的引用不会被视为易失性"我应该怎么想?

produces warning "a reference to a volatile field will not be treated as volatile" What should I think about this?

推荐答案

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

There are numerous questions here. Considering them one at a time:

引用分配是原子的,为什么需要 Interlocked.Exchange(ref Object, Object)?

reference assignment is atomic so why is Interlocked.Exchange(ref Object, Object) needed?

引用分配是原子的.Interlocked.Exchange 不只做引用分配.它读取变量的当前值,隐藏旧值,并将新值分配给变量,所有这些都是原子操作.

Reference assignment is atomic. Interlocked.Exchange does not do only reference assignment. It does a read of the current value of a variable, stashes away the old value, and assigns the new value to the variable, all as an atomic operation.

我的同事说在某些平台上不能保证引用分配是原子的.我的同事说得对吗?

my colleague said that on some platforms it's not guaranteed that reference assignment is atomic. Was my colleague correct?

没有.引用分配保证在所有 .NET 平台上都是原子的.

No. Reference assignment is guaranteed to be atomic on all .NET platforms.

我的同事从错误的前提进行推理.这是否意味着他们的结论是错误的?

My colleague is reasoning from false premises. Does that mean that their conclusions are incorrect?

不一定.你的同事可能会出于不好的原因给你很好的建议.也许您应该使用 Interlocked.Exchange 有其他一些原因.无锁编程极其困难,一旦您偏离了该领域专家所拥护的完善实践,您就会陷入困境,并冒着最糟糕的竞争条件的风险.我既不是该领域的专家,也不是您的代码方面的专家,因此我无法以任何方式做出判断.

Not necessarily. Your colleague could be giving you good advice for bad reasons. Perhaps there is some other reason why you ought to be using Interlocked.Exchange. Lock-free programming is insanely difficult and the moment you depart from well-established practices espoused by experts in the field, you are off in the weeds and risking the worst kind of race conditions. I am neither an expert in this field nor an expert on your code, so I cannot make a judgement one way or the other.

产生警告对易失性字段的引用不会被视为易失性"我应该怎么想?

produces warning "a reference to a volatile field will not be treated as volatile" What should I think about this?

您应该明白为什么这是一个普遍的问题.这将有助于理解为什么警告在这种特殊情况下不重要.

You should understand why this is a problem in general. That will lead to an understanding of why the warning is unimportant in this particular case.

编译器给出这个警告的原因是因为将一个字段标记为 volatile 意味着这个字段将在多个线程上更新——不要生成任何缓存这个字段值的代码,并确保任何读取或该字段的写入不会通过处理器缓存不一致在时间上前后移动".

The reason that the compiler gives this warning is because marking a field as volatile means "this field is going to be updated on multiple threads -- do not generate any code that caches values of this field, and make sure that any reads or writes of this field are not "moved forwards and backwards in time" via processor cache inconsistencies."

(我假设您已经了解了所有这些.如果您没有详细了解 volatile 的含义以及它如何影响处理器缓存语义,那么您就不了解它的工作原理,也不应该使用 volatile.Lock- 免费程序很难正确;确保您的程序正确,因为您了解它的工作原理,而不是偶然正确.)

(I assume that you understand all that already. If you do not have a detailed understanding of the meaning of volatile and how it impacts processor cache semantics then you don't understand how it works and should not be using volatile. Lock-free programs are very difficult to get right; make sure that your program is right because you understand how it works, not right by accident.)

现在假设您通过将 ref 传递给该字段来创建一个变量,该变量是该字段的别名.在被调用的方法中,编译器没有任何理由知道引用需要具有易变语义!编译器会高兴地为无法实现易失性字段规则的方法生成代码,但变量 易失性字段.那会完全破坏你的无锁逻辑;假设始终是使用 volatile 语义总是访问 volatile 字段.有时将其视为 volatile 而不是其他时候是没有意义的;您必须始终保持一致,否则无法保证其他访问的一致性.

Now suppose you make a variable which is an alias of a volatile field by passing a ref to that field. Inside the called method, the compiler has no reason whatsoever to know that the reference needs to have volatile semantics! The compiler will cheerfully generate code for the method that fails to implement the rules for volatile fields, but the variable is a volatile field. That can completely wreck your lock-free logic; the assumption is always that a volatile field is always accessed with volatile semantics. It makes no sense to treat it as volatile sometimes and not other times; you have to always be consistent otherwise you cannot guarantee consistency on other accesses.

因此,当您这样做时,编译器会发出警告,因为它可能会完全弄乱您精心开发的无锁逻辑.

Therefore, the compiler warns when you do this, because it is probably going to completely mess up your carefully developed lock-free logic.

当然,Interlocked.Exchange 是为了期望一个易变的字段并做正确的事情而编写的.因此,该警告具有误导性.我非常后悔;我们应该做的是实现某种机制,通过这种机制,像 Interlocked.Exchange 这样的方法的作者可以在方法上放置一个属性,说这个采用 ref 的方法对变量强制执行易失性语义,因此禁止警告".也许在编译器的未来版本中我们会这样做.

Of course, Interlocked.Exchange is written to expect a volatile field and do the right thing. The warning is therefore misleading. I regret this very much; what we should have done is implement some mechanism whereby an author of a method like Interlocked.Exchange could put an attribute on the method saying "this method which takes a ref enforces volatile semantics on the variable, so suppress the warning". Perhaps in a future version of the compiler we shall do so.

这篇关于引用分配是原子的,为什么需要 Interlocked.Exchange(ref Object, Object) ?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆