私は、実装が簡単に見える問題について考えていましたが、効率的でスレッドセーフなソリューションが私を悩ませています。私がやりたいのは、ある種のワーカーオブジェクトを作成することです。複数の呼び出し元が、異なるスレッドから動作するように要求する場合があります。要件は、リクエストがキューに入れられてはならないということです。言い換えれば、誰かが労働者に仕事をするように頼んだが、それがすでに仕事をしているのを見た場合、それはただ早く戻るべきです。
簡単な最初のパスはこれです:
@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];
});
}
@終わり
これはスレッドセーフであると私は信じていますが、頻繁にロック(高価な操作)を取得して放棄しなければならないのはかなり厄介だと思います。
それで、よりエレガントな解決策はありますか?