【问题标题】:When should each thread synchronization objects be used?什么时候应该使用每个线程同步对象?
【发布时间】:2009-04-17 12:10:00
【问题描述】:

在什么情况下应该使用以下各个同步对象?

  1. ReaderWriter 锁
  2. 信号量
  3. 互斥体

【问题讨论】:

  • 在我看来它是一个问题(标题+列表),只是问得很糟糕。对我来说没有直接关闭的理由,他可以像其他人一样编辑它以更具体。
  • 这个“问题”显然没有单一的答案,但它肯定会产生很多非常有趣的评论。例如,RW 锁的效率通常低于简单的互斥锁。
  • 这个问题需要改写。但这是一个问题。这家伙正在询问这些特定工​​具的用例。投票重新开放

标签: c# multithreading synchronization


【解决方案1】:
  • 由于每次调用 post() 时 wait() 将返回一次,因此信号量是基本的生产者-消费者模型 - 线程间消息的最简单形式,可能是信号除外。使用它们是为了让一个线程可以告诉另一个线程它感兴趣的事情发生了(以及发生了多少次),并用于管理对最多可以拥有固定有限数量用户的资源的访问。它们提供多线程代码所需的排序保证。

  • 互斥体按照他们在锡上所说的做 - “互斥”。它们确保访问某些资源的权利一次仅由线程“持有”。这保证了多线程代码所需的原子性和排序。在大多数操作系统上,它们还提供相当复杂的服务员行为,尤其是为了避免优先级倒置。

请注意,信号量可以很容易地用于实现互斥,但是由于信号量没有“所有者线程”,因此您无法使用信号量来避免优先级反转。所以它们并不适合所有需要“锁”的用途。

  • ReaderWriter 锁是对互斥锁的优化,在您有很多争用的情况下,大多数访问是只读的,并且允许同时读取受保护的数据结构。在这种情况下,只有当涉及到作者时才需要排除——读者不需要相互排除。为了将一个读者提升为写者,所有其他读者必须在获得写者锁之前完成(或者如果他们也希望成为写者,则中止并开始等待重试)。 ReaderWriter 锁在速度不快的情况下可能会变慢,因为它们对互斥锁进行了额外的记账。

  • 条件变量用于允许线程等待某些事实或事实组合为真,其中所讨论的条件比信号量的“它已被戳”或“没有其他人正在使用”更复杂它”用于互斥锁和读写器锁的编写器部分,或者“没有编写器正在使用它”用于读写器锁的读取器部分。它们也用于不同等待线程的触发条件不同,但取决于部分或全部相同状态(内存位置或其他)的情况。

  • 自旋锁适用于当您在一个处理器或内核上等待很短的时间(如几个周期),而另一个内核(或 I/O 总线等硬件)同时做一些你关心的工作。在某些情况下,它们比信号量或中断等其他原语提供了性能增强,但必须非常小心地使用(因为在现代内存模型中无锁算法很困难)并且只有在证明有必要时(因为避免系统原语的聪明想法通常是过早的优化)。

顺便说一句,这些答案不是 C# 特定的(因此例如关于“大多数操作系统”的评论)。 Richard 提出了一个很好的观点,即在 C# 中你应该在适当的地方使用普通的旧锁。我相信监视器是一个互斥体/条件变量对组合到一个对象中。

【讨论】:

    【解决方案2】:

    我会说他们每个人都可以是“最好的” - 取决于用例;-)

    【讨论】:

      【解决方案3】:

      简单的答案:几乎从不。

      最好的锁定类型是不需要锁(无共享可变状态)。

      如果您确实需要锁,请尝试使用 Monitor(通过 lock 语句),除非您对不同的东西有特定需求(在这种情况下,请参阅 Onebyone 的回答

      此外,比起ReaderWriterLock,更喜欢ReaderWriteLockSlim(除了要求后者公平的极少数情况)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-08
        • 2016-07-28
        • 2023-04-10
        • 2012-06-28
        • 2016-05-09
        • 2023-03-24
        相关资源
        最近更新 更多