Objective c NSMutableDictionary线程安全
我对使用Objective c NSMutableDictionary线程安全,objective-c,nsmutabledictionary,Objective C,Nsmutabledictionary,我对使用NSMutableDictionary时的线程安全性有疑问 主线程正在从NSMutableDictionary读取数据,其中: 键是NSString 值为UIImage 异步线程正在将数据写入上述字典(使用NSOperationQueue) 如何使上述词典线程安全 我应该使NSMutableDictionary属性原子化吗?或者我需要做任何额外的更改吗 @property(retain)NSMutableDictionary*dicNamesWithPhotosNSMutableDi
NSMutableDictionary
时的线程安全性有疑问
主线程正在从NSMutableDictionary
读取数据,其中:
- 键是
NSString
- 值为
UIImage
NSOperationQueue
)
如何使上述词典线程安全
我应该使NSMutableDictionary
属性原子化吗?或者我需要做任何额外的更改吗
@property(retain)NSMutableDictionary*dicNamesWithPhotos
NSMutableDictionary
不是为线程安全的数据结构而设计的,仅仅将属性标记为原子的
,并不能确保底层数据操作实际上是以原子方式(以安全的方式)执行的
为确保以安全的方式完成每个操作,您需要使用锁保护字典上的每个操作:
// in initialization
self.dictionary = [[NSMutableDictionary alloc] init];
// create a lock object for the dictionary
self.dictionary_lock = [[NSLock alloc] init];
// at every access or modification:
[object.dictionary_lock lock];
[object.dictionary setObject:image forKey:name];
[object.dictionary_lock unlock];
您应该考虑自己滚动<代码> NSCORCHONE/COD>,只需调用NStutabLy字典中的一个锁:
@interface SafeMutableDictionary : NSMutableDictionary
{
NSLock *lock;
NSMutableDictionary *underlyingDictionary;
}
@end
@implementation SafeMutableDictionary
- (id)init
{
if (self = [super init]) {
lock = [[NSLock alloc] init];
underlyingDictionary = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void) dealloc
{
[lock_ release];
[underlyingDictionary release];
[super dealloc];
}
// forward all the calls with the lock held
- (retval_t) forward: (SEL) sel : (arglist_t) args
{
[lock lock];
@try {
return [underlyingDictionary performv:sel : args];
}
@finally {
[lock unlock];
}
}
@end
请注意,因为每个操作都需要等待并持有锁,所以它的可伸缩性不强,但在您的情况下可能已经足够好了
如果要使用适当的线程库,可以使用多线程安全库,因为它们有TKMutableDictionary
。我个人没有使用过它,而且它似乎是一个正在开发的库,但您可能想尝试一下。经过一点研究,我想与您分享这篇文章:
在多线程应用程序中安全地使用集合类
看来诺普的答案终究不是一个解决方案。从线程的角度来看,这是可以的,但有一些关键的微妙之处。我不会在这里发布解决方案,但我想这篇文章中有一个很好的解决方案 我有两个使用nsmutabledictionary的选项
一是:
NSLock* lock = [[NSLock alloc] init];
[lock lock];
[object.dictionary setObject:image forKey:name];
[lock unlock];
二是:
//Let's assume var image, name are setup properly
dispatch_async(dispatch_get_main_queue(),
^{
[object.dictionary setObject:image forKey:name];
});
我不知道为什么有些人想要覆盖可变字典的设置和获取。即使答案是正确的,也有一个优雅而不同的解决方案:
- (id)init {
self = [super init];
if (self != nil) {
NSString *label = [NSString stringWithFormat:@"%@.isolation.%p", [self class], self];
self.isolationQueue = dispatch_queue_create([label UTF8String], NULL);
label = [NSString stringWithFormat:@"%@.work.%p", [self class], self];
self.workQueue = dispatch_queue_create([label UTF8String], NULL);
}
return self;
}
//Setter, write into NSMutableDictionary
- (void)setCount:(NSUInteger)count forKey:(NSString *)key {
key = [key copy];
dispatch_async(self.isolationQueue, ^(){
if (count == 0) {
[self.counts removeObjectForKey:key];
} else {
self.counts[key] = @(count);
}
});
}
//Getter, read from NSMutableDictionary
- (NSUInteger)countForKey:(NSString *)key {
__block NSUInteger count;
dispatch_sync(self.isolationQueue, ^(){
NSNumber *n = self.counts[key];
count = [n unsignedIntegerValue];
});
return count;
}
当使用线程不安全对象时,副本很重要,这样可以避免由于意外释放变量而可能出现的错误。不需要线程安全实体
如果更多队列希望使用NSMutableDictionary,请声明专用队列并将setter更改为:
self.isolationQueue = dispatch_queue_create([label UTF8String], DISPATCH_QUEUE_CONCURRENT);
- (void)setCount:(NSUInteger)count forKey:(NSString *)key {
key = [key copy];
dispatch_barrier_async(self.isolationQueue, ^(){
if (count == 0) {
[self.counts removeObjectForKey:key];
} else {
self.counts[key] = @(count);
}
});
}
重要强>
您必须设置自己的专用队列,而不使用它。dispatch\u barrier\u sync只是一个简单的dispatch\u sync
详细解释如下。现在你可能会选择@synchronized(object)
...
@synchronized(dictionary) {
[dictionary setObject:image forKey:name];
}
...
@synchronized(dictionary) {
[dictionary objectForKey:key];
}
...
@synchronized(dictionary) {
[dictionary removeObjectForKey:key];
}
不再需要NSLock
对象了我不是多线程方面的专家,但我知道“原子”标志(@synthetic'd访问器的默认标志)不能保证线程安全。不过,当我第一次读到它时,我也有同样的想法。这看起来是一个很棒的方法,但我无法编译它。我在“retval”之前得到了-(retval)forward:(SEL)SEL:(arglist)args
有什么想法吗?非常好的答案。现在已经过时了。改为使用队列。我在某处有一本非常简单的连载词典。我应该把它寄出去。邮件转发速度慢且脆弱。请跟进bbum的评论。在Mike Ash的博客上有一篇关于将GCD并发队列与NSMutableDictionary结合使用的有用文章:@bbum您是否曾经发布过您的序列化词典的示例?使用@sychronized使其安全如何?+1注意到在这种情况下锁定是不够的。我也曾被这个问题困扰过一次,[[[dict objectForKey:key]retain]autorelease]
在多线程环境中,“技巧”确实是必要的。这个链接现在已经断了,技术说明是从2002年开始的。您最好使用-1,因为它几乎(但不是完全)是一个链接唯一的答案。这与@ProoEntry(atomic)dictionary不一样吗?不,这意味着用一个全新的实例替换dictionary是原子的。不改变字典中的任何一个元素。非常感谢!这是救命稻草。