在C#中锁定关键字

时间:2008-09-12 17:38:50

标签: c# multithreading design-patterns locking

我理解来自MSDN的锁定关键字的主要功能

  

lock语句(C#参考)

     

lock关键字标记一个语句   阻止作为一个关键部分   获得互斥锁   对于给定的对象,执行一个   声明,然后发布   锁。

什么时候应该使用锁?

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

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

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

请注意,这更多是一般知识问题,申请速度很好,我想知道这是否是一个好的设计模式,或者除非绝对需要,否则应该避免这样做。

10 个答案:

答案 0 :(得分:58)

  

什么时候应该使用锁?

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

  

但是当应用程序没有关闭任何其他线程时是否有必要?

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

  

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

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

  

...如果这是一个好的设计模式,将来会有[?]

无所事事地锁定一切都是一种糟糕的设计模式。如果您的代码混乱了随机锁定,然后您决定使用后台线程进行某些工作,那么您可能会遇到死锁。在多个线程之间共享资源需要仔细设计,并且越能分离出棘手的部分,就越好。

答案 1 :(得分:7)

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

代码被标记为关键的影响是,如果整个区域无法完全执行,运行时可能会认为您的整个Application Domain可能受到危害,因此会从内存中卸载它。引用MSDN

  

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

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

有关详细信息,请阅读this article on the perils of Thread.Abort()

答案 2 :(得分:6)

请记住,可能有理由说明您的应用程序不像您想象的那样是单线程的。例如,.NET中的异步I / O可能会在池线程上回调,就像某些各种计时器类(不是Windows窗体计时器)一样。

答案 3 :(得分:2)

一般来说,如果你的应用程序是单线程的,你就不会在lock语句中得到很多用处。我不确切知道你的应用程序,我不知道它们是否有用 - 但我怀疑不是。此外,如果您的应用程序在任何地方使用锁定,我不知道我会对在多线程环境中工作感到充满信心 - 原始开发人员实际上知道如何开发多线程代码,或者他们只是在模糊的地方添加锁定语句,希望能够解决这个问题吗?

答案 4 :(得分:2)

应该在修改共享状态的代码周围使用

锁,其他线程同时修改的状态,以及那些其他步骤必须采用相同的锁。

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

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

如果您对多线程性能感兴趣,一个好的起点是MSDN threading guidelines

答案 5 :(得分:1)

可能会出现锁定变量的性能问题,但通常情况下,您需要构建代码以最大限度地缩短在“锁定”代码块中花费的时间长度。

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

答案 6 :(得分:1)

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

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

答案 7 :(得分:1)

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

并且锁定会调用性能命中,添加指令以在执行代码之前检查同时访问。它只应在必要时使用。

答案 8 :(得分:1)

在C#中查看question关于'Mutex'的内容。然后查看有关使用'lock(Object)'语句的these two个问题。

答案 9 :(得分:0)

如果只有一个线程,那么在应用程序中拥有锁是没有意义的,是的,这是一个性能命中,尽管它确实需要相当多的调用才能将该命中堆叠成重要的东西。