在什么情况下应该使用以下每个同步对象?
答案 0 :(得分:5)
因为每次调用post()时wait()都会返回一次,所以信号量是一个基本的生产者 - 消费者模型 - 除了信号之外最简单的线程间消息形式。它们被使用,因此一个线程可以告诉另一个线程发生了它感兴趣的事情(以及多少次),以及管理对最多只能拥有固定有限数量用户的资源的访问。它们提供多线程代码所需的订购保证。
互斥体按照他们对锡的说法 - “相互排斥”。它们确保访问某些资源的权限一次只能在线程上“保留”。这样可以保证多线程代码所需的原子性和排序。在大多数操作系统中,它们还提供相当复杂的服务员行为,特别是为了避免优先级倒置。
请注意,信号量可以很容易地用于实现互斥,但由于信号量没有“所有者线程”,因此您不会通过信号量获得优先级反转。因此它们不适合所有需要“锁定”的用途。
ReaderWriter锁是对互斥锁的优化,如果您有很多争用,大多数访问都是只读的,并且允许同时读取受保护的数据结构。在这种情况下,只有在涉及作者时才需要排除 - 读者不需要彼此排除。为了促进读者写作,所有其他读者必须在获得作者锁之前完成(或中止并开始等待他们也希望成为作者时重试)。 ReaderWriter锁在速度不快的情况下可能会更慢,因为它们会通过互斥锁进行额外的簿记。
条件变量用于允许线程等待某些事实或事实组合为真,其中所讨论的条件比信号量“已被戳”更复杂,或“没有其他人使用它“对于互斥体和读写器锁定的作者部分,或”没有作者正在使用它“作为读写器锁的读者部分。它们也用于不同等待线程的触发条件不同的情况,但取决于部分或全部相同的状态(内存位置或其他)。
旋转锁用于在一个处理器或内核上等待很短的时间(如几个周期),同时另一个内核(或I / O总线等硬件)做一些你关心的工作。在某些情况下,它们比其他原语(如信号量或中断)提供性能增强,但必须非常谨慎地使用(因为现代内存模型中的无锁算法很困难)并且只有在证明有必要时才会使用(因为明智的想法可以避免使用系统原语)往往是过早的优化。)
顺便说一下,这些答案不是C#特定的(因此例如关于“大多数操作系统”的评论)。理查德提出了一个很好的观点,即在C#中你应该使用普通的旧锁。我相信监视器是一个互斥/条件变量对,它们被集成到一个对象中。
答案 1 :(得分:1)
我会说他们每个人都可以“最好” - 取决于用例; - )
答案 2 :(得分:1)
简单回答:几乎没有。
最好的锁定类型是不需要锁定(没有共享的可变状态)。
如果您确实需要锁定,请尝试使用监视器(通过锁定语句),除非您对不同的东西有特定需求(在这种情况下请参阅Onebyone的答案
此外,更喜欢ReaderWriteLockSlim
到ReaderWriterLock
(除非极少数情况下要求后者公平)。