我一直在思考一个看似很容易实现的问题,但一个高效且线程安全的解决方案却让我感到困扰。我想做的是创建某种工作对象。几个调用者可能会要求它从不同的线程工作。一个要求是请求不能排队。换句话说,如果有人要求工人工作,但看到它已经在工作,它应该早点回来。
一个简单的第一关是这样的:
@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 属性不是线程安全的。将其标记为原子在这里无济于事,因为对它的访问需要在几个语句之间同步。
为了使其线程安全,我需要使用锁来保护 isWorking:
@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];
});
}
@结尾
虽然我确实相信这将是线程安全的,但我认为不得不如此频繁地获取和放弃锁(一项昂贵的操作)是非常糟糕的。
那么,有没有更优雅的解决方案呢?