1

約 10 個のワーカー スレッドが同時にアクセスするブロッキング キューの作成に取り組んでいます。キューの基本的な実装は次のようになります。

-(void) enqueue:(__strong id)value
{
    [_mutex lock];

    while ([self size] == _maxSize) {
        [_mutex wait];
    }

    [_queue enqueue:value];
    [_mutex signal];
    [_mutex unlock];
}

-(id) dequeue
{    
    [_mutex lock];

    while ([self isEmpty]) {
        [_mutex wait];
    }

    id value = [_queue dequeue];
    [_mutex broadcast];

    [_mutex unlock];
    return value;
}

はどこ_mutexですかNSCondition-isEmptyおよび-sizeメソッドには問題があります。

-(int) size
{
    @try {
        [_mutex lock];

        return [_queue size];
    }
    @finally {
        [_mutex unlock];        
    }
}

-(BOOL) isEmpty
{
    @try {
        [_mutex lock];

        return [_queue isEmpty];
    }
    @finally {    
        [_mutex unlock];
    }
}

データが破損していないことを確認するためにミューテックスをロックする必要があるため、NSCondition再帰的にロックしないため、プログラムがデッドロックに陥ります。ただし、実装を次のように変更すると:

-(void) enqueue:(__strong id)value
{
    while ([self size] == _maxSize) {
        [_mutex lock];
        [_mutex wait];
        [_mutex unlock];
    }

    [_mutex lock];
    [_queue enqueue:value];
    [_mutex signal];
    [_mutex unlock];
}

-(id) dequeue
{
    while ([self isEmpty]) {
        [_mutex lock];
        [_mutex wait];
        [_mutex unlock];
    }

    [_mutex lock]; // when I require the lock here, another thread has already dequeued the object
    id value = [_queue dequeue];
    [_mutex broadcast];

    [_mutex unlock];
    return value;
}

その後、プログラムはデッドロックしませんが、ロックを再取得するまでに、別のワーカーが既に必要なオブジェクトをキューから取り出しています。NSCondition再帰を作成する方法について何か考えはありますか?

4

2 に答える 2

1

私は通常、次のパターンを使用します。

-(int)primitiveSize
{
  return [_queue size];
}

ObjC で接頭辞が付いたメソッドprimitive(Core Data 命名の伝統に由来) は、副作用がなく、おかしなビジネスもなく、変換もなく、価値を与えるだけであることを示唆しています。このようにprimitiveSizeして、カプセル化を放棄することなく、すでにロックを取得している場合に使用できます。

これは、再帰的ミューテックス BTW を作成するよりもはるかに高速です。

于 2012-02-03T15:01:16.757 に答える
0

再帰ミューテックスを実装する NSCondition クラスのドロップイン置換を実装しました: https://github.com/bradley219/NSRecursiveCondition

于 2014-02-12T23:49:30.463 に答える