我不知道LINQ的扩展方法是原子? 或者我需要lock
任何IEnumerable
跨线程使用的对象,任何类型的迭代过吗?
不声明变量作为volatile
有任何关于此影响?
综上所述,下列哪项是最好的,线程安全的,运行?
1无任何锁:
IEnumerable<T> _objs = //...
var foo = _objs.FirstOrDefault(t => // some condition
2-包括锁语句:
IEnumerable<T> _objs = //...
lock(_objs)
{
var foo = _objs.FirstOrDefault(t => // some condition
}
3-声明变量作为易失性:
volatile IEnumerable<T> _objs = //...
var foo = _objs.FirstOrDefault(t => // some condition
接口IEnumerable<T>
不是线程安全。 查看文档http://msdn.microsoft.com/en-us/library/s793z9y2.aspx ,其中规定:
一个枚举只要集合保持不变,仍然有效。 如果改变对集合进行,例如添加,修改或删除元素时,枚举是失效且不可恢复其行为是不确定的。
枚举数没有对集合的独占访问; 因此,通过集合枚举是本质上不是一个线程安全的过程。 要枚举过程中保证线程安全,可以在整个枚举过程中锁定集合。 要允许由多个线程用于读取和写入访问的集合,则必须实现自己的同步。
LINQ不改变任何这一点。
锁定显然可以用来同步访问对象。 你必须锁定随处可见,虽然访问的对象,在它迭代不只是当。
声明收集挥发性不会有任何积极的作用。 它只是导致读取之前的存储器屏障和参考集合的写操作后。 它不同步采集读取或写入。
总之,如上所述,它们不是线程安全的。
然而,这并不意味着你必须在锁定“每样重复的。”
你需要同步的是改变集合中的所有操作(添加,修改或删除元素)与其它操作(添加,修改,删除元素,或读取元素)。
如果你只在集合执行读操作的同时,无需锁定。 (所以运行LINQ命令,如平均,包含,ElementAtOrDefault一起就可以了)
如果集合中的元素是机器字长,如int在大多数32位计算机的,则改变已经原子方式执行该元素的值。 在这种情况下,不添加或删除集合元素没有锁定,但修改的值可能是好的,如果你能处理你的设计的一些非确定性。
最后,可以考虑在单个元素或部分的集合,而不是锁定整个集合细粒度锁。