C#锁和新手多线程问题

时间:2012-08-12 19:38:12

标签: c# multithreading

关于.NET中多线程的一些新手问题,我认为这有助于强化我想要吸收的一些概念 - 我已经阅读了几种多线程材料(包括Albahari电子书),但我觉得我只需要一些确认一些问题,以帮助推动这些概念回家

  1. 锁定范围保护共享的代码区域 - 假设有一个线程正在执行一个方法,该方法在循环中递增一个简单的整数变量x - 但是这不会保护其他可能也会改变变量x的代码,例如在另一个线程上的另一种方法...

    由于这是可能影响同一变量的两个不同的代码区域,我们是否通过使用相同的锁定变量锁定两个代码区域来解决这个问题?如果你用不同的锁变量锁定了两个代码区域,这不能保护变量的正确吗?

  2. 为了进一步说明这个例子,使用相同的锁变量,如果由于某种原因,一个方法中的代码进入某个无限循环并且永远不会放弃锁变量会发生什么 - 如何在第二个代码区域中其他方法检测到这个?

  3. 锁变量的选择如何影响锁的行为?我已经阅读了很多关于这个主题的帖子,但似乎永远无法找到明确的答案 - 在某些情况下,人们明确地使用了一个专门用于此目的的对象变量,有时人们使用锁定(这个),最后有时候我已经看到人们使用类型对象。

    锁定变量的不同选择如何影响锁定的行为/范围以及使用其中一种方法有什么意义呢?

  4. 假设你有一个包含在类中的哈希表,暴露了add,remove,get和某种Calculate方法(比如每个对象代表一个数量,这个方法对每个值求和)并且所有这些方法都被锁定 - 但是,一旦引用对于该集合中的一个对象可用于其他代码并在应用程序中传递,该对象(不是散列表)现在将在该类的方法周围的锁定范围之外。那么您可以保护对这些对象的访问/更新从哈希表中获取的实际对象可能会干扰Calculate方法吗?
  5. 感谢任何有助于为我强化这些概念的启发式方法 - 谢谢!

2 个答案:

答案 0 :(得分:2)

1)是

2)这是一个僵局

3)您要阻止的代码部分是您的类的实现细节。使用lock(this)lock(this.GetType())公开锁定对象会遇到麻烦,因为现在外部代码可能会锁定同一个对象并无意或恶意地阻止您的代码。锁定对象应该是私有的。

4)你的意思并不清楚,你当然不想直接公开Hashtable。只需将它保存为类的私有字段,将其封装起来。

但是,使用线程安全地将类暴露给客户端代码的可能性会随着公开的公共方法和属性的数量而迅速下降。您将很快达到只有客户端代码可以正确锁定的程度。当客户端代码持有属性值时,细粒度锁定为线程竞争创造了大量机会。说出您返回的Count属性值。当使用值时,就像在for循环中一样,Count属性可能已更改。只有最谨慎的设计才能避免这些陷阱,这是一个严重的问题。

此外,细粒度锁定效率非常低,因为它不可避免地在代码的最内部部分完成。锁不是 昂贵,粗糙的100 cpu周期,但它很快就会增加。如果类对象实际上没有在多个线程中使用,那么特别浪费了精力。

您没有选择,只能声明您的类线程不安全,客户端代码需要以线程安全的方式使用它。这也是许多.NET类不是线程安全的核心原因。这是线程难以正确处理的最大原因,程序员最不可能正确地执行它是最困难的事情。

答案 1 :(得分:1)

1) 你是对的。您必须使用相同的锁定对象来保护两个不同区域的代码,例如增加变量x。

2) 这被称为死锁,是多线程编程的难点之一。有些算法可用于防止死锁,例如Bankers算法。

3) 有些语言使锁定变得容易,例如在.Net中,您可以创建一个对象并将其用作共享锁。这适用于在给定进程内同步代码。锁(this)只是将锁应用于相关对象。但是请尽量避免这种情况,而是创建一个私有对象并使用它。锁定(这)可能导致死锁情况。下面的锁定对象可能只是一个关键部分的包装器。如果你想跨越不同的进程保护资源,你需要一个更重的名为Mutex,这需要锁定一个内核对象并且价格昂贵,所以除非你必须这样做,否则不要使用。

4)你需要确保在那里也应用锁定。但是当人们在这个引用上调用方法时,他们肯定会调用采用同步的方法。

相关问题