2

ConditionJava では、複数のオブジェクトを 1 つの に関連付けることができますReentrantLock。C#に相当するものは何ですか?

実際の例: JavaConditionドキュメントの実装例では、同じロックに結び付けられたとの 2 つのConditionオブジェクトを使用しています。その例をどのように C# に変換できますか?notFullnotEmpty

背景Condition: 2 つのオブジェクトを使用して、同じオブジェクトに関連付けられたさまざまな状態を通知するJava コードをよく見かけますLock。C#では、次のいずれかができるようです

  • Monitor.Enterオブジェクトを呼び出してからMonitor.WaitOne/を呼び出しますMonitor.Pulseが、これは 1 つの条件にすぎません。
  • 複数のAuto/ManualResetEventオブジェクトを使用しますが、これらは待機後に特定のロックをアトミックに再取得できません。

: 1 つの方法を考えることができます:単一のオブジェクトでMonitor.WaitOne/を使用し、ウェイクアップ後に状態をチェックします。Monitor.PulseAllこれは、偽のウェイクアップから保護するために、Java でも行うことです。ただし、別の条件で待機しているスレッドを起動する可能性があるため、PulseAllの代わりに呼び出す必要があるため、実際にはそうではありません。残念ながら、代わりに使用すると、パフォーマンスに影響があります (スレッドが同じロックを求めて競合します)。PulsePulsePulseAllPulse

4

3 に答える 3

1

新しい開発を行っていて、.NET 4 以降を実行できる場合は、 ConcurrentQueueなどの新しい並行コレクション クラスがより適切に機能すると思います。

しかし、あなたがその動きをすることができず、あなたの質問に厳密に答えることができない場合、.NET ではこれはいくらか単純化されています。prod/cons パターンを実装するには、待機してから以下のようにパルスします (これを入力したことに注意してくださいメモ帳)

// 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はロックを解放するため、デッドロックは発生しないことに注意してください。

于 2013-10-23T17:57:14.667 に答える
0

@Jasonキューがいっぱいで、スレッドが1つしか起こらない場合、スレッドが消費者であることは保証されません。それはプロデューサーかもしれません。

于 2013-10-23T18:38:27.780 に答える
0

ロック内で状態を共有したい C# コードはあまり見たことがありません。自分でロールバックしなくても、 a を使用できます(ただし、 orSemaphoreSlimをお勧めします)。ConcurrentQueue(T)BlockingCollection(T)

public class BoundedBuffer<T>
{
    private readonly SemaphoreSlim _locker = new SemaphoreSlim(1,1);
    private readonly int _maxCount = 1000;
    private readonly Queue<T> _items;

    public int Count { get { return _items.Count; } }

    public BoundedBuffer()
    {
        _items = new Queue<T>(_maxCount);
    }

    public BoundedBuffer(int maxCount)
    {
        _maxCount = maxCount;
        _items = new Queue<T>(_maxCount);
    }

    public void Put(T item, CancellationToken token)
    {
        _locker.Wait(token);

        try
        {
            while(_maxCount == _items.Count)
            {
                _locker.Release();
                Thread.SpinWait(1000);
                _locker.Wait(token);
            }

            _items.Enqueue(item);
        }
        catch(OperationCanceledException)
        {
            try
            {
                _locker.Release();
            }
            catch(SemaphoreFullException) { }

            throw;
        }
        finally
        {
            if(!token.IsCancellationRequested)
            {
                _locker.Release();
            }
        }
    }

    public T Take(CancellationToken token)
    {
        _locker.Wait(token);

        try
        {
            while(0 == _items.Count)
            {
                _locker.Release();
                Thread.SpinWait(1000);
                _locker.Wait(token);
            }

            return _items.Dequeue();
        }
        catch(OperationCanceledException)
        {
            try
            {
                _locker.Release();
            }
            catch(SemaphoreFullException) { }

            throw;
        }
        finally
        {
            if(!token.IsCancellationRequested)
            {
                _locker.Release();
            }
        }
    }
}
于 2013-10-23T19:21:07.990 に答える