C# IEnumerable Linq方法是线程安全的吗?

C# IEnumerable Linq方法是线程安全的吗?,c#,multithreading,thread-safety,atomic,C#,Multithreading,Thread Safety,Atomic,我想知道Linq扩展方法是否是原子的?或者在任何类型的迭代之前,我是否需要锁定跨线程使用的任何IEnumerable对象 将变量声明为volatile是否会对此产生任何影响 总之,以下哪项是最好的线程安全操作 1-不带任何锁: IEnumerable<T> _objs = //... var foo = _objs.FirstOrDefault(t => // some condition IEnumerable<T> _objs = //... lock(_ob

我想知道Linq扩展方法是否是原子的?或者在任何类型的迭代之前,我是否需要
锁定跨线程使用的任何
IEnumerable
对象

将变量声明为
volatile
是否会对此产生任何影响

总之,以下哪项是最好的线程安全操作

1-不带任何锁:

IEnumerable<T> _objs = //...
var foo = _objs.FirstOrDefault(t => // some condition
IEnumerable<T> _objs = //...
lock(_objs)
{
    var foo = _objs.FirstOrDefault(t => // some condition
}
volatile IEnumerable<T> _objs = //...
var foo = _objs.FirstOrDefault(t => // some condition
IEnumerable\u objs=/。。。
var foo=_objs.FirstOrDefault(t=>//某些条件
2-包括锁定语句:

IEnumerable<T> _objs = //...
var foo = _objs.FirstOrDefault(t => // some condition
IEnumerable<T> _objs = //...
lock(_objs)
{
    var foo = _objs.FirstOrDefault(t => // some condition
}
volatile IEnumerable<T> _objs = //...
var foo = _objs.FirstOrDefault(t => // some condition
IEnumerable\u objs=/。。。
锁(_objs)
{
var foo=_objs.FirstOrDefault(t=>//某些条件
}
3-将变量声明为volatile:

IEnumerable<T> _objs = //...
var foo = _objs.FirstOrDefault(t => // some condition
IEnumerable<T> _objs = //...
lock(_objs)
{
    var foo = _objs.FirstOrDefault(t => // some condition
}
volatile IEnumerable<T> _objs = //...
var foo = _objs.FirstOrDefault(t => // some condition
volatile IEnumerable\u objs=/。。。
var foo=_objs.FirstOrDefault(t=>//某些条件

接口
IEnumerable
不是线程安全的。请参阅上的文档,其中说明:

只要集合保持不变,枚举数就保持有效。如果对集合进行了更改(如添加、修改或删除元素),则枚举数将不可恢复地失效,并且其行为未定义

枚举器没有对集合的独占访问权限;因此,通过集合进行枚举本质上不是线程安全的过程。为保证枚举期间的线程安全,可以在整个枚举期间锁定集合。若要允许多个线程访问集合进行读写,请y您必须实现自己的同步

Linq不会改变这一切

锁定显然可以用于同步对对象的访问。但是,您必须在访问对象的任何地方锁定对象,而不仅仅是在对其进行迭代时


将集合声明为volatile不会产生任何积极影响。它只会在读取集合引用之前和写入集合引用之后产生内存障碍。它不会同步集合的读取或写入。

简而言之,它们不是上述线程安全的

然而,这并不意味着您必须在“每种迭代”之前锁定

您需要将更改集合的所有操作(添加、修改或删除元素)与其他操作(添加、修改、删除元素或读取元素)同步

如果您只是同时对集合执行读取操作,则不需要锁定。(因此,同时运行诸如Average、Contains、ElementAtOrDefault等LINQ命令就可以了)

如果集合中的元素具有机器字长度,如大多数32位计算机上的Int,则更改该元素的值已以原子方式执行。在这种情况下,在不锁定的情况下,不要从集合中添加或删除元素,但如果可以处理设计中的某些不确定性,则修改值可能是可以的。

最后,可以考虑对集合的各个元素或部分进行细粒度锁定,而不是锁定整个集合。

它们不是线程安全的。参见