我理解来自MSDN的锁定关键字的主要功能
lock语句(C#引用)lock关键字通过获取给定对象的互斥锁,执行语句,然后释放锁来将语句块标记为关键部分 .
什么时候应该使用锁?
例如,它对多线程应用程序有意义,因为它可以保护数据 . 但是,当应用程序没有关闭任何其他线程时,它是否有必要?
使用锁存在性能问题吗?
我刚刚继承了一个在任何地方使用锁的应用程序,它是单线程的,我想知道我应该留下它们,它们甚至是必要的吗?
请注意,这更多是一般知识问题,应用程序速度很好,我想知道这是否是将来要遵循的良好设计模式,或者除非绝对需要,否则应该避免这种情况 .
10 回答
应使用锁来保护多线程代码中的共享资源 . 不是别的 .
绝对不 . 这只是浪费时间 . 但是请确保您没有隐式使用系统线程 . 例如,如果您使用异步I / O,您可能会收到来自随机线程的回调,而不是原始线程 .
是 . 它们在单线程应用程序中不是很大,但为什么要拨打你不需要的电话呢?
无所事事地锁定一切都是一种糟糕的设计模式 . 如果您的代码混乱了随机锁定,然后您决定使用后台线程进行某些工作,那么您可能会遇到死锁 . 在多个线程之间共享资源需要仔细设计,并且越能分离出棘手的部分就越好 .
这里的所有答案都是正确的:锁的用处是阻止线程同时访问锁定的代码 . 但是,这个领域有许多细微之处,其中一个是公共语言运行时自动将锁定的代码块标记为 critical regions .
代码被标记为关键的影响是,如果整个区域无法完全执行,运行时可能会认为您的整个Application Domain可能受到危害,因此会从内存中卸载它 . 引用MSDN:
因此,即使您的应用程序是单线程的,这可能对您有害 . 考虑锁定块中的一个方法抛出最终未在块内处理的异常 . 即使异常发生在它通过调用堆栈冒泡时,您的关键代码区域也无法正常完成 . 谁知道CLR会如何反应?
有关详细信息,请阅读this article on the perils of Thread.Abort() .
请记住,可能有原因导致您的应用程序不像您想象的那样是单线程的 . 例如,.NET中的异步I / O可能会在池线程上回调,就像一些各种计时器类(不是Windows窗体计时器)一样 .
一般来说,如果您的应用程序是单线程的,那么你知道他们是否在任何地方都使用了锁定我不知道我会对它在多线程环境中工作充满信心 - 原来的开发人员实际上是这样的知道如何开发多线程代码,或者他们只是在模糊的地方添加锁定语句,希望能做到这一点?
应该在修改共享状态的代码周围使用锁,同时由其他线程修改的状态,以及那些其他步骤必须采用相同的锁 .
锁实际上是一个内存访问序列化程序,线程(采取锁定)将等待锁进入,直到当前线程退出锁,因此内存访问被序列化 .
为了回答你问题,在单线程应用程序中不需要锁定,它确实具有性能副作用 . 因为C#中的锁是基于内核同步对象的,所以每次锁都会创建一个从用户转换到内核模式的过程模式 .
如果你对多线程性能感兴趣,一个好的起点是MSDN threading guidelines
锁定变量可能会出现性能问题,但通常情况下,您锁定了“代码块” .
至于取下锁 . 这取决于代码究竟在做什么 . 即使它是单线程的,如果你的对象被实现为Singleton,你可能会有多个客户端同时使用它的一个实例(在内存中,在服务器上) .
是的,使用锁时会有一些性能损失,但通常可以忽略不计 .
使用锁(或任何其他互斥语句或构造)通常仅在多线程场景中需要,其中多个线程(您自己制作或来自您的调用者)有机会与对象交互并更改基础状态或数据维持 . 例如,如果您有一个可以被多个线程访问的集合,则您不希望一个线程通过在另一个线程尝试读取它时删除该项来更改该集合的内容 .
锁(令牌)仅用于标记不应在多个线程中同时运行的一个或多个代码块 . 如果您的应用程序是单线程的,那么它可以防止不存在的情况 .
并且锁定会调用性能命中,添加指令以在执行代码之前检查同时访问 . 它只应在必要时使用 .
请参阅C#中的question关于'Mutex' . 然后查看these two有关使用'lock(Object)'声明的问题 .
如果只有一个线程,那么在应用程序中拥有锁是没有意义的,是的,这是一个性能命中,尽管它确实需要相当多的调用才能将该命中重叠成重要的内容 .