7

一些关于 .NET 中多线程的新手问题,我认为这将有助于强化我正在尝试吸收的一些概念——我已经阅读了一些多线程材料(包括 Albahari 电子书),但我觉得我只需要确认一些问题帮助将这些概念带回家

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

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

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

  3. 锁变量的选择如何影响锁的行为?我已经阅读了很多关于这个主题的帖子,但似乎永远找不到明确的答案——在某些情况下,人们明确地为此目的使用对象变量,其他时候人们使用 lock(this),最后我'见过人们使用类型对象。

    锁变量的不同选择如何影响锁的行为/范围,在哪些场景中使用其中一个更有意义?

  4. 假设您有一个包含在一个类中的哈希表,该类公开 add、remove、get 和某种计算方法(例如,每个对象代表一个数量,并且此方法对每个值求和)并且所有这些方法都被锁定 - 但是,一旦对对象的引用在该集合可供其他代码使用并通过应用程序传递时,该对象(不是哈希表)现在将位于该类方法周围的锁定范围之外..然后您如何保护对这些实际对象的访问/更新来自哈希表,这可能会干扰计算方法?

感谢提供的任何启发式方法,这将有助于加强我的这些概念 - 谢谢!

4

2 回答 2

2

1) 是的

2)这是一个僵局

3)您要阻止的代码部分是您的类的实现细节。通过使用lock(this)lock(this.GetType())自找麻烦来暴露锁定对象,因为现在外部代码可以锁定同一个对象并无意或恶意地阻止您的代码。锁定对象应该是私有的。

4)您的意思不是很清楚,您当然不想直接公开哈希表。只需将其保留为类的私有字段,将其封装即可。

但是,您可以使用线程安全地将您的类公开给客户端代码的几率随着公开的公共方法和属性的数量而迅速下降。您将很快达到只有客户端代码才能正确锁定的地步。当客户端代码保持属性值时,细粒度锁定为线程竞争创造了很多机会。说出您返回的 Count 属性值。到它使用该值时,例如在 for 循环中,Count 属性可能已更改。只有最细心的设计才能避开这些陷阱,真是让人头疼。

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

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

于 2012-08-12T20:10:32.977 回答
1

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

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

3) 某些语言使锁定变得容易,例如在.Net 中,您可以创建一个对象并将其用作共享锁。这对于在给定进程中同步代码很有用。Lock(this) 只是将锁应用于有问题的对象。但是尽量避免这种情况,而是创建一个私有对象并使用它。Lock(this) 可能导致死锁情况。下面的锁定对象可能只是关键部分的包装。如果您想跨不同进程保护资源,您将需要一个更重的命名互斥锁,这需要锁定内核对象并且成本很高,因此除非必须,否则不要使用。

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

于 2012-08-12T19:50:10.120 回答