【问题标题】:C# locks and newbie multithreading questionsC#锁和新手多线程问题
【发布时间】:2012-08-12 19:38:12
【问题描述】:

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

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

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

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

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

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

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

【问题讨论】:

  • 每个问题一个问题,请。
  • @JohnSaunders - 通常是的,但这是一系列(强烈)相关的问题。
  • 请不要关闭它。这个问题很有用,并且有有用的答案。子问题属于一起。
  • @usr:Stack Overflow 不是这样工作的。如果他愿意,OP 应该提出单独的问题,并包括所有问题的链接,但它们需要是单独的问题。这不是一个讨论论坛。

标签: c# multithreading


【解决方案1】:

1) 是的

2) 这是一个死锁

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

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • 问题是,如果 Get 方法返回一个引用/指向底层集合中任意对象的指针(例如 .NET 中的 Object 类的实例),一旦引用,您如何保护该对象它由封装存储对象的集合的类返回,但不是对象本身,例如,一旦从同步的 Get 方法返回引用并将应用程序传递到其他线程不安全的代码区域?我猜这是不可能的,除非任意对象本身有同步方法来保护自己的状态,对吗?
    • 如果您从 Get 方法返回的对象是并且应该受到保护,那么您将遇到麻烦。好的设计将确保您不会简单地从应受保护的方法内部“泄漏”(返回)内容。因为那时调用者是开放的来操纵这个对象。现在你有两段代码可以改变这个对象,只有一段是受保护的。您的代码不再是线程安全的。
    猜你喜欢
    • 2020-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多