使用LINQ查询进行C#锁定

Ric*_*cky 8 .net c# linq synchronization thread-safety

是否有必要按如下方式锁定LINQ语句?如果省略锁定,当多个线程同时执行时,任何异常都会被反击?

lock (syncKey)
{
    return (from keyValue in dictionary
            where keyValue.Key > versionNumber
            select keyValue.Value).ToList();
}
Run Code Online (Sandbox Code Playgroud)

PS:编写者线程确实存在以改变字典.

Col*_*kay 5

只要查询没有副作用(例如调用代码进行更改的任何表达式),就不需要锁定LINQ语句.

基本上,如果您不修改数据(并且没有其他任何东西正在修改您正在使用的数据),那么您不需要锁定.

如果您使用的是.NET 4.0,那么ConcurrentDictionary是线程安全的.这是一个使用并发字典的例子(诚​​然不在LINQ语句中)

UPDATE

如果要修改数据,则需要使用锁.如果两个或多个线程尝试访问锁定的代码段,则会有一个小的性能损失,因为一个或多个线程等待释放锁.注意:如果您过度锁定,那么如果您从一开始就使用顺序算法构建代码,那么您可能会遇到更糟糕的性能.

如果您只是在读数据,那么您不需要锁,因为没有可保护的可变共享状态.

如果你不使用锁,那么你最终可能会遇到数据不正确的间歇性错误,或者当读者和作者之间发生冲突时会抛出异常.根据我的经验,大多数时候你可能永远不会得到异常,你只是得到了损坏的数据(除了你不一定知道它已经腐败).下面是另一个示例,说明如果不使用锁或重新设计算法来处理数据,数据是如何被破坏的.

如果考虑从一开始就在并行系统中进行开发的限制,您通常可以从系统中获得最佳效果.有时您可以重新编写代码,因此它不使用共享数据.有时您可以将数据拆分为块并让每个线程/任务在其自己的块上工作,然后在最后将一些进程再次拼接在一起.


Mar*_*ell 5

大多数类型对于read是线程安全的,但在突变期间不是线程安全的。

如果没有任何线程正在更改字典,那么您无需执行任何操作- 只需阅读即可。

但是,如果其中一个线程正在更改它,那么您就会遇到问题并需要同步。最简单的方法是 a lock,但是即使没有写入器,这也会阻止并发读取器。如果很有可能你有更多的读者而不是作者,请考虑使用 aReaderWriterLockSlim来同步 - 这将允许任意数量的读者(没有作者),或者:一个作者。

在 4.0 中,您可能还会考虑 ConcurrentDictionary<,>


aba*_*hev 3

如果您的字典是静态的,并且运行查询的方法不是静态的(或其他并发访问方案),并且可以从另一个线程修改字典,那么是的,需要锁,否则 - 则不需要。

  • 它不必是静态的——只需可以从多个线程访问即可。 (4认同)