【发布时间】:2019-08-02 04:05:46
【问题描述】:
我在 GCD 中实现了这个读写器锁,但在并行测试中失败了。我可以解释为什么它失败了吗?
这是用于 iOS 开发的。该代码基于Objective C。我在GCD中编写了一个带有读写器锁的RWCache,用于数据保护。
@interface RWCache : NSObject
- (void)setObject:(id)object forKey:(id <NSCopying>)key;
- (id)objectForKey:(id <NSCopying>)key;
@end
@interface RWCache()
@property (nonatomic, strong) NSMutableDictionary *memoryStorage;
@property (nonatomic, strong) dispatch_queue_t storageQueue;
@end
@implementation RWCache
- (instancetype)init {
self = [super init];
if (self) {
_memoryStorage = [NSMutableDictionary new];
_storageQueue = dispatch_queue_create("Storage Queue", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
- (void)setObject:(id)object forKey:(id <NSCopying>)key {
dispatch_barrier_async(self.storageQueue, ^{
self.memoryStorage[key] = object;
});
}
- (id)objectForKey:(id <NSCopying>)key {
__block id object = nil;
dispatch_sync(self.storageQueue, ^{
object = self.memoryStorage[key];
});
return object;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
RWCache *cache = [RWCache new];
dispatch_queue_t testQueue = dispatch_queue_create("Test Queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < 100; i++) {
dispatch_group_async(group, testQueue, ^{
[cache setObject:@(i) forKey:@(i)];
});
dispatch_group_async(group, testQueue, ^{
[cache objectForKey:@(i)];
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}
return 0;
}
如果没有死锁,程序退出0,否则程序挂起不退出。
【问题讨论】:
-
我不完全确定您的代码为什么会死锁,但这似乎是一种非常复杂的共享字典访问方式。一个简单的
NSLock就可以解决问题......并且效率提高大约 100 倍。 -
@JamesBucanek 你是对的。这可能效率不高。我只是尝试在 GCD 中实现读/写锁,看看它是如何工作的,我也想知道为什么它会导致这个演示的死锁。
-
我不会认为它的效率会降低。对其进行基准测试。上次我对它进行基准测试时,读写器速度要快得多......
-
@Rob,很公平。但我想区分fast 和efficient。我承认,在某些极端情况下,这样的读写方案可能会为这样的
O(1)操作运行得更快——但它不可能更高效。我的证据是,读取操作将涉及至少两个线程切换,以及由(可能是多个)信号量和屏障操作控制的块的伴随排队和出队。这不可能击败单个(可能没有争议的)信号量。 (“高效”定义为每瓦所做的功) -
@Rob Sidebar:对于 OP,这是一个练习,很好。我的观点是关于现实世界的应用程序,尤其是针对移动设备的应用程序——尽管我认为我们桌面开发人员也应该尽自己的一份力量来提高软件的效率。
标签: ios concurrency grand-central-dispatch deadlock readerwriterlock