代码之家  ›  专栏  ›  技术社区  ›  Raj

NSMutableDictionary线程安全

  •  37
  • Raj  · 技术社区  · 16 年前

    我对使用时的线程安全性有疑问 NSMutableDictionary .

    易变词典 哪里:

    • 关键是 NSString
    • UIImage

    异步线程正在将数据写入上述字典(使用 NSOperationQueue )

    我应该去吗 财产 atomic

    @property(retain) NSMutableDictionary *dicNamesWithPhotos;

    5 回复  |  直到 12 年前
        1
  •  75
  •   Stavash    10 年前

    NSMutableDictionary 不是设计为线程安全的数据结构,只是将属性标记为 atomic ,不能确保底层数据操作实际上是以原子方式(以安全的方式)执行的。

    为确保以安全的方式完成每个操作,您需要使用锁保护字典上的每个操作:

    // 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];
    

    你应该考虑自己滚动。 NSDictionary 只需在持有锁的同时将调用委托给NSMutableDictionary:

    @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
    

    如果要使用适当的线程库,可以使用 TransactionKit library 正如他们所做的那样 TKMutableDictionary 这是一个多线程安全库。我个人还没有使用过它,而且它似乎是一个正在开发的库,但您可能想尝试一下。

        2
  •  5
  •   P.Melch    8 年前

    现在你可能会去 @synchronized(object)

    ...
    @synchronized(dictionary) {
        [dictionary setObject:image forKey:name];
    }
    ...
    @synchronized(dictionary) {
        [dictionary objectForKey:key];
    }
    ...
    @synchronized(dictionary) {
        [dictionary removeObjectForKey:key];
    }
    

    不需要 NSLock 再反对吗

        3
  •  2
  •   Hertzel Guinness    12 年前

    http://developer.apple.com/library/mac/#technotes/tn2002/tn2059.html

    看来诺普的答案终究不是一个解决方案。从线程的角度来看,这是可以的,但有一些关键的微妙之处。我不会在这里发布解决方案,但我想这篇文章中有一个很好的解决方案。

        4
  •  1
  •   Roman Marusyk S Kotra    10 年前

    一是:

    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];
    });
    

    我不知道为什么有些人想覆盖可变字典的设置和获取。

        5
  •  1
  •   BootMaker    10 年前

    - (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);
        }
    });
    }
    

    重要!

    您必须设置自己的专用队列,而不使用它 调度\u屏障\u同步 这只是一个简单的问题 调度同步

    详细解释见本节 marvelous blog article