关于C#中的multithreading:lock关键字

关于C#中的multithreading:lock关键字

lock keyword in C#

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

lock Statement (C# Reference)

The lock keyword marks a statement
block as a critical section by
obtaining the mutual-exclusion lock
for a given object, executing a
statement, and then releasing the
lock.

什么时候应该使用锁?

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

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

我刚刚继承了一个在所有地方都使用锁的应用程序,它是单线程的,我想知道是否应该保留它们,甚至有必要吗?

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


When should the lock be used?

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

But is it necessary when the application does not spin off any other threads?

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

Is there performance issues with using lock?

是。它们在单线程应用程序中不是很大,但是为什么要拨打不需要的电话呢?

...if that is a good design pattern to follow in the future[?]

随意锁定所有内容是一种糟糕的设计模式。如果您的代码由于随机锁定而混乱不堪,然后您决定使用后台线程进行某些工作,则很可能会遇到死锁。在多个线程之间共享资源需要进行仔细的设计,并且您可以将棘手的部分隔离得越多越好。


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

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

For example, consider a task that attempts to allocate memory while holding a lock. If the memory allocation fails, aborting the current task is not sufficient to ensure stability of the AppDomain, because there can be other tasks in the domain waiting for the same lock. If the current task is terminated, other tasks could be deadlocked.

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

有关更多信息,请阅读Thread.Abort()的风险方面的这篇文章。


请记住,您的应用程序可能不像您想象的那样具有单线程的原因。例如,.NET中的异步I / O可能会在池线程上进行回调,就像各种计时器类中的某些类一样(虽然不是Windows Forms Timer)。


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

锁实际上是一个内存访问序列化程序,(带该锁的)线程将等待该锁进入,直到当前线程退出该锁为止,以便对内存访问进行序列化。

要回答您的问题,在单线程应用程序中不需要锁,它确实会对性能产生副作用。因为C#中的锁基于内核同步对象,并且您获得的每个锁都会从用户模式过渡到内核模式。

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


一般来说,如果您的应用程序是单线程的,则不会在lock语句中获得太多使用。不完全了解您的应用程序,我不知道它们是否有用-但我怀疑没有用。此外,如果您的应用程序在所有地方都使用锁,那么我不知道我是否会对在多线程环境中使用锁充满信心-原始开发人员实际上是否知道如何开发多线程代码,还是他们只是在模糊的希望中到处添加锁定语句,希望能达到目的?


请参阅C#中有关" Mutex"的问题。然后看看这两个与使用" lock(Object)"语句有关的问题。


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

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


是的,使用锁时会降低性能,但是通常可以忽略不计。

通常仅在多线程方案中使用锁(或任何其他互斥语句或构造),在多线程方案中,多个线程(由您自己创建或来自调用者)可以与对象进行交互并更改基础状态或数据已维护。例如,如果您有一个可由多个线程访问的集合,则您不希望一个线程通过在另一个线程尝试读取一个项目时删除该项目来更改该集合的内容。


锁定变量可能会导致性能问题,但是通常情况下,您可以构造代码以最大程度地减少"锁定"代码块中花费的时间。

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


如果只有一个线程,则在应用程序中锁定是没有意义的,是的,虽然确实需要大量的调用才能使该命中率提高为重要水平,但它却对性能有很大的影响。


推荐阅读