2009-12-31 26 views
35

NSMutableDictionary numaralı telefonu kullanırken iş parçacığı güvenliği hakkında bir sorum var.NSMutableDictionary iş parçacığı güvenliği

ana iş parçacığı burada NSMutableDictionary veri okuma:

  • anahtar NSString
  • değeri UIImage

Zaman uyumsuz iplik sözlük üzerinde

( NSOperationQueue kullanılarak) veri yazma olduğunu

Yukarıdaki sözlük dizisini nasıl güvenli hale getirebilirim?

NSMutableDictionary özelliği atomic mı yapmalıyım? Veya herhangi bir ek değişiklik yapmam gerekiyor mu?

@property(retain) NSMutableDictionary *dicNamesWithPhotos;

+2

Çoklu iş parçacığı konusunda uzman değilim, ancak "atomik" işaretlemenin (sentezlemeli erişimciler için varsayılan) iş parçacığı güvenliği konusunda hiçbir garanti vermediğini biliyorum. Yine de, bunu ilk kez okurken aynı şeyi düşündüm. –

cevap

69

NSMutableDictionary evreli veri yapısı için tasarlanmamıştır ve sadece atomic olarak özelliği, işaretleme temel veri operasyonları aslında (güvenli bir şekilde) atomik gerçekleştirilir garanti etmez.

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

Sen NSMutableDictionary çağrıları kendi NSDictionary o basitçe delegelere haddeleme düşünmelisiniz:

her işlem güvenli bir şekilde yapıldığından emin olmak için, bir kilit ile sözlüğe her operasyon korumak gerekir bir kilit tutarak: her işlem o kilit bekliyor ve holding gerektirdiğinden
@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 

lütfen unutmayın, oldukça ölçeklenebilir değil, ama senin durumunda yeterince iyi olabilir.

Uygun bir dişli kitaplığı kullanmak isterseniz, çok iş parçacıklı bir güvenli kitaplık olan TKMutableDictionary olduğundan TransactionKit library kullanabilirsiniz. Şahsen kullanmadım ve devam eden bir çalışma kütüphanesi gibi görünüyor, ama denemek isteyebilirsiniz.

+7

+1 muhteşem yanıt –

+2

Bu harika bir yöntem gibi görünüyor ama derlemeyi başaramıyorum. Ben "beklenen") 'önce' retval_t ''' satırında '- (retval_t) ileri: alıyorum: (SEL) sel: (arglist_t) args' Herhangi bir fikir? –

+5

Muhteşem cevap. Şimdi modası geçmiş. Bunun yerine bir sıra kullanın. Bir yerlerde basit bir seri hale getirilmiş sözlük var. Göndermeliyim. Mesaj iletimi yavaş ve kırılgandır. – bbum

1

seninle bu makaleyi paylaşmak istiyorum araştırma biraz sonra: çoklu kullanım uygulamalarında http://developer.apple.com/library/mac/#technotes/tn2002/tn2059.html

Bu notnoop yanıt gibi görünüyor ile güvenle toplama sınıflarını kullanma

sonuçta bir çözüm olmayabilir. İş parçacığı perspektifinden tamam, ama bazı önemli incelikler var. Buraya bir çözüm yollamayacağım ama sanırım bu makalede iyi bir tane var.

+1

+1. Ben bir kez de bu tarafından ısırıldı, '[[[dict objectForKey: key] korumak] autorelease]' hile 'gerçekten çok iş parçacıklı bir ortamda gereklidir. – DarkDust

+4

Bu bağlantı artık kesildi ve teknik not 2002'den geliyor. Https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html ile daha iyi durumda olabilirsiniz. –

+0

-1 Neredeyse (ama oldukça değil, bu yüzden işaretlemekten kaçınmak için) bir bağlantı sadece bir cevaptır. – ArtOfWarfare

1

nsmutabledictionary kullanmanın iki seçeneğim var.

biri şudur:

NSLock* lock = [[NSLock alloc] init]; 
[lock lock]; 
[object.dictionary setObject:image forKey:name]; 
[lock unlock]; 

İki: Ben bazı insanlar ayarlama ve mutabledictionary inerek üzerine yazmak istiyor neden bilmiyorum

//Let's assume var image, name are setup properly 
dispatch_async(dispatch_get_main_queue(), 
^{ 
     [object.dictionary setObject:image forKey:name]; 
}); 

.

1

bile cevap zarif ve farklı çözüm yoktur, doğrudur:, iplik güvensiz nesneleri kullanarak bu konuda nedeniyle değişkenin istenmeyen salımının olası hatayı önlemek olabilir zaman

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

kopya önemlidir . İş parçacığı güvenli varlıklara gerek yok.

daha kuyruk özel kuyruğu beyan NSMutableDictionary kullanması ve ayarlayıcı değiştirmek isterseniz:

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

ÖNEMLİ!

Sen dispatch_barrier_sync

Detaylı açıklama bu marvelous blog article olduğunu sadece basit dispatch_sync olduğunu onsuz bir kendi özel kuyruk ayarlamak zorunda.

İlgili konular