43

我从 MSDN 了解 lock 关键字的主要功能

lock 语句(C# 参考)

lock 关键字通过获取给定对象的互斥锁、执行语句然后释放锁来将语句块标记为临界区。

什么时候应该使用锁?

例如,它对多线程应用程序很有意义,因为它可以保护数据。但是当应用程序不分离任何其他线程时是否有必要?

使用锁是否存在性能问题?

我刚刚继承了一个在任何地方都使用锁的应用程序,它是单线程的,我想知道我应该把它们留在里面,它们甚至是必要的吗?

请注意,这更像是一个常识性问题,应用程序速度很好,我想知道这是否是将来要遵循的良好设计模式,或者除非绝对需要,否则应该避免这种情况。

4

10 回答 10

58

什么时候应该使用锁?

应该使用锁来保护多线程代码中的共享资源。不为别的。

但是当应用程序不分离任何其他线程时是否有必要?

绝对不。这只是浪费时间。但是请确保您没有隐式使用系统线程。例如,如果您使用异步 I/O,您可能会收到来自随机线程的回调,而不是原始线程。

使用锁是否存在性能问题?

是的。它们在单线程应用程序中不是很大,但为什么要进行不需要的调用呢?

...如果这是一个很好的设计模式在未来[?]

随意锁定所有内容是一种糟糕的设计模式。如果您的代码被随机锁定弄得杂乱无章,然后您决定使用后台线程进行某些工作,那么您很可能会遇到死锁。在多个线程之间共享资源需要仔细设计,越能隔离棘手的部分越好。

于 2008-09-12T17:49:43.557 回答
7

这里的所有答案似乎都是正确的:锁的用处是阻止线程同时访问锁定的代码。然而,这个领域有很多微妙之处,其中之一是公共语言运行时会自动将锁定的代码块标记为关键区域

代码被标记为关键的影响是,如果整个区域无法完全执行,运行时可能会认为您的整个应用程序域可能受到威胁,因此,将其从内存中卸载。引用MSDN

例如,考虑一个在持有锁的同时尝试分配内存的任务。如果内存分配失败,中止当前任务并不足以保证 AppDomain 的稳定性,因为域中可能还有其他任务在等待同一个锁。如果当前任务终止,其他任务可能会死锁。

因此,即使您的应用程序是单线程的,这对您来说也可能是一个危险。考虑锁定块中的一种方法会引发异常,该异常最终不会在块内处理。即使异常在调用堆栈中冒泡时得到处理,您的关键代码区域也没有正常完成。谁知道 CLR 会如何反应?

有关更多信息,请阅读这篇关于 Thread.Abort() 的危险的文章

于 2008-09-13T04:18:13.203 回答
6

请记住,您的应用程序不像您想象的那样单线程可能是有原因的。.NET 中的异步 I/O 可以很好地回调池线程,例如,一些不同的计时器类(但不是 Windows 窗体计时器)也是如此。

于 2008-09-12T17:52:37.933 回答
2

一般来说,如果您的应用程序是单线程的,那么您不会从 lock 语句中获得太多用处。不完全了解您的应用程序,我不知道它们是否有用 - 但我怀疑不是。此外,如果您的应用程序在任何地方都使用锁,我不知道我是否会对它在多线程环境中工作充满信心 - 原始开发人员是否真的知道如何开发多线程代码,或者他们只是在模糊的希望中到处添加锁定语句,这样可以解决问题吗?

于 2008-09-12T17:41:23.497 回答
2

lock 应该在修改共享状态的代码周围使用,由其他线程同时修改的状态,并且那些其他线程必须采用相同的锁。

锁实际上是一个内存访问序列化器,线程(获取锁)将等待锁进入,直到当前线程退出锁,因此内存访问被序列化。

要回答您的问题,单线程应用程序中不需要锁,并且它确实具有性能副作用。因为 C# 中的锁是基于内核同步对象的,并且您使用的每个锁都会创建从用户模式到内核模式的转换。

如果您对多线程性能感兴趣,那么MSDN 线程指南是一个不错的起点

于 2008-09-12T17:48:32.200 回答
1

可能会遇到锁定变量的性能问题,但通常,您会构建代码以最小化在“锁定”代码块内花费的时间长度。

至于拆锁。这将取决于代码到底在做什么。即使它是单线程的,如果您的对象是作为单例实现的,那么您可能会有多个客户端同时使用它的实例(在内存中,在服务器上)。

于 2008-09-12T17:43:40.637 回答
1

是的,使用锁时会有一些性能损失,但通常可以忽略不计。

使用锁(或任何其他互斥语句或构造)通常只在多线程场景中需要,其中多个线程(您自己创建或来自您的调用者)有机会与对象交互并更改底层状态或数据保持。例如,如果您有一个可以被多个线程访问的集合,您不希望一个线程在另一个线程试图读取它时通过删除一个项目来更改该集合的内容。

于 2008-09-12T17:44:15.630 回答
1

Lock(token) 仅用于标记不应在多个线程中同时运行的一个或多个代码块。如果您的应用程序是单线程的,那么它可以防止出现不存在的情况。

锁定确实会导致性能下降,在执行代码之前添加指令以检查同时访问。它只应在必要时使用。

于 2008-09-12T17:46:06.747 回答
1

请参阅C# 中有关“互斥”的问题。然后看看 两个关于使用'lock(Object)'语句的问题。

于 2008-09-12T20:08:25.860 回答
0

如果只有一个线程,那么在应用程序中加锁是没有意义的,是的,它会影响性能,尽管确实需要相当多的调用才能使该命中累积成重要的东西。

于 2008-09-12T17:42:35.820 回答