在等待之前释放锁定,然后重新获取锁定 [英] Release a lock before waiting, and re-acquire it after

查看:227
本文介绍了在等待之前释放锁定,然后重新获取锁定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Java中,您可以将多个条件对象关联到单个 ReentrantLock 。 C#等价物是什么?

In Java, you can associate multiple Condition objects to a single ReentrantLock. What would the C# equivalent be?

真实示例: Java 条件文档使用两个条件对象, notFull notEmpty ,绑在同一个锁上。如何将该示例转换为C#?

Real-world example: The example implementation in the Java Condition documentation uses two Condition objects, notFull and notEmpty, tied to the same lock. How could that example be translated to C#?

背景:我经常使用两个条件用于指示各种状态的对象,与相同的 Lock 相关联;在C#中,似乎你可以

Background: I often find Java code using two Condition objects to signal various states, associated to the same Lock; in C#, it seems that you can either


  • 调用 Monitor.Enter 对象,然后 Monitor.WaitOne / Monitor.Pulse ,但这只是一个条件。

  • 使用多个 Auto / ManualResetEvent 对象,但这些对象在等待后无法以原子方式重新获取给定的锁。

  • call Monitor.Enter on an object, and then Monitor.WaitOne/Monitor.Pulse, but that's just one condition.
  • use multiple Auto/ManualResetEvent objects, but these cannot atomically reacquire a given lock after waiting.

注意:我可以想到一种方法:使用 Monitor.WaitOne / 监控.PulseAll 在一个物体上,并在醒来后检查状况;这就是你用Java做的事情,以防止虚假的唤醒。但它并没有真正做到,因为它迫使你调用 PulseAll 而不是 Pulse ,因为 Pulse 可能会唤醒等待另一个条件的线程。不幸的是,使用 PulseAll 而不是 Pulse 会影响性能(线程竞争同一个锁)。

Note: I can think of one way: using Monitor.WaitOne/Monitor.PulseAll on a single object, and checking for the condition after waking up; that's what you do in Java as well to protect against spurious wake-ups. It doesn't really do, though, because it forces you to call PulseAll instead of Pulse, since Pulse might wake up a thread waiting on another condition. Unfortunately, using PulseAll instead of Pulse has performance implications (threads competing for the same lock).

推荐答案

我认为如果您正在进行新的开发并且可以执行.NET 4或更高版本,那么新的并发集合类将为您提供更好的服务,例如 ConcurrentQueue

I think if you are doing new development and can do .NET 4 or above, you'll be better served by the new concurrent collection classes, like ConcurrentQueue.

但是,如果你不能做出这一举动,并严格回答你的问题,在.NET中这有点简化imho,实现一个prod / cons模式你只需要等待然后如下脉冲(注意我在记事本上键入此内容)

But if you can't make that move, and to strictly answer your question, in .NET this is somewhat simplified imho, to implement a prod/cons pattern you would just do wait and then pulse like below (note that I typed this on notepad)

// max is 1000 items in queue
private int _count = 1000;

private Queue<string> _myQueue = new Queue<string>();

private static object _door = new object();

public void AddItem(string someItem)
{
    lock (_door)
    {
        while (_myQueue.Count == _count)
        {
            // reached max item, let's wait 'till there is room
            Monitor.Wait(_door);
        }

        _myQueue.Enqueue(someItem);
        // signal so if there are therads waiting for items to be inserted are waken up
        // one at a time, so they don't try to dequeue items that are not there
        Monitor.Pulse(_door);
    }
}

public string RemoveItem()
{
    string item = null;

    lock (_door)
    {
        while (_myQueue.Count == 0)
        {
            // no items in queue, wait 'till there are items
            Monitor.Wait(_door);
        }

        item = _myQueue.Dequeue();
        // signal we've taken something out
        // so if there are threads waiting, will be waken up one at a time so we don't overfill our queue
        Monitor.Pulse(_door);
    }

    return item;
}

更新:要清除任何混淆,请注意 Monitor.Wait 释放锁定,因此你不会陷入僵局

Update: To clear up any confusion, note that Monitor.Wait releases a lock, therefore you won't get a deadlock

这篇关于在等待之前释放锁定,然后重新获取锁定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆