0

私は、実装が簡単に見える問題について考えていましたが、効率的でスレッドセーフなソリューションが私を悩ませています。私がやりたいのは、ある種のワーカーオブジェクトを作成することです。複数の呼び出し元が、異なるスレッドから動作するように要求する場合があります。要件は、リクエストがキューに入れられてはならないということです。言い換えれば、誰かが労働者に仕事をするように頼んだが、それがすでに仕事をしているのを見た場合、それはただ早く戻るべきです。

簡単な最初のパスはこれです:

@interface Worker : NSObject
@property (nonatomic, assign, getter = isWorking) BOOL working;
- (void)doWork;
@end

@implementation Worker
{
    dispatch_queue_t _workerQueue; //... a private serial queue
}

- (void)doWork
{
    if ( self.isWorking )
    {
        return;
    }
    self.working = YES;
    dispatch_async(_workerQueue, ^{
        // Do time consuming work here ... Done!
        self.working = NO;
    });
}
@end

これに伴う問題は、isWorkingプロパティがスレッドセーフではないことです。アトミックとしてマークすることは、アクセスをいくつかのステートメント間で同期する必要があるため、ここでは役に立ちません。

スレッドセーフにするには、isWorkingwithlockを保護する必要があります。

@interface Worker : NSObject
@property (nonatomic, assign, getter = isWorking) BOOL working;
- (void)doWork;
@end

@implementation Worker
{
    dispatch_queue_t _workerQueue; //... a private serial queue
    NSLock *_lock; // assume this is created
}

- (void)doWork
{
    [_lock lock];
    if ( self.isWorking )
    {
        [_lock unlock];
        return;
    }
    self.working = YES;
    [_lock unlock];
    dispatch_async(_workerQueue, ^{
        // Do time consuming work here ... Done!
        [_lock lock];
        self.working = NO;
        [_lock unlock];
    });
}

@終わり

これはスレッドセーフであると私は信じていますが、頻繁にロック(高価な操作)を取得して放棄しなければならないのはかなり厄介だと思います。

それで、よりエレガントな解決策はありますか?

4

3 に答える 3

3

dispatch_semaphoreすでにGCDを使用している場合、有限のリソースへのアクセスを制限する慣用的な方法です。

// Add an ivar:
dispatch_semaphore_t _semaphore;

// To initialize:
_semaphore = dispatch_semaphore_create(1);

// To "do work" from any thread:
- (void)doWork
{
     if (dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_NOW) == 0) {
         // We got the semaphore without waiting, so we're first in line.
         dispatch_async(_workerQueue, ^{
             // do time consuming work here, then when done:
             dispatch_semaphore_signal(_semaphore);
         });
     } else {
         // We would have had to wait for the semaphore, so somebody must have
         // been doing work already, and we should do nothing.
     }
}

これがより詳細に説明しているブログ投稿です。

于 2013-01-10T06:33:43.517 に答える
2

ここで、アトミックテストアンドセット操作を使用できる場合があります。GCCは__atomic_test_and_setこの目的のために提供します。C(未テスト)での使用方法は次のとおりです。

static volatile bool working = FALSE;
if(__atomic_test_and_set(&working, __ATOMIC_ACQUIRE)) {
    // Already was working.
}else{
    // Do work, possibly in another thread.
    // When done:
    __atomic_clear(&working, __ATOMIC_RELEASE);
}

簡単ですね

于 2013-01-10T06:20:10.590 に答える
0

プロパティをスレッドセーフにするために、@synchronizeを使用するだけです。

于 2013-01-10T06:22:19.373 に答える