2015-05-29 93 views
4

我有一個「sharedStore」 - 模式的單身人士的NSMutableArray。NSMutableArray線程併發與GCD

公開地說,它只能通過將其轉換爲NSArray的方法訪問。在類,它是

@property (nonatomic, copy) NSMutableArray *myItems; 

這個數組永遠不會被操縱outsdie單身,但ViewControllers發送單消息來操作該控制器。其中一些消息清空陣列,一些重新填充它,等等。

已經結束了在一個方法調用中數組爲空而下一個方法尚未空的情況下,我開始實現一些併發行爲。

下面是我在做什麼至今:

在單身的.m文件,我有一個

@property (nonatomic, strong) dispatch_queue_t arrayAccessQueue; 

在我單身的初始化它被創建爲一個串行隊列。然後,每一個有什麼關係改變此數組從dispatch_sync電話中這樣做,例如方法:

dispatch_sync(self.arrayAccessQueue, ^{ 
    [_myItems removeAllObjects]; 
}); 

這更好的事情做,並取得了我的應用程序表現得更加順暢。然而,除了修正上述一個奇怪的行爲之外,我無法量化它。我也覺得我在黑暗中可能潛伏在表面之下的任何問題。

這種模式對我有意義,但我應該使用別的東西,如@synchronizeNSLockNSOperationQueue?這會回來咬我嗎?

+0

順便說一句 - 你是否正確地爲你的'myItems'屬性實現了一個明確的setter方法?如果不是,由於mutable屬性上的'copy'屬性,你將會遇到問題。 – rmaddy

+0

嗯。我不知道。你的意思是'_myItems = [myItems copy]'?我認爲編譯器現在自動執行了這個操作,而且它不需要再明確地完成了?我錯了嗎? – magiclantern

+1

問題在於[myItems copy]返回一個'NSArray',而不是'NSMutableArray',即使在可變數組上調用時也是如此。你需要重寫'setMyItems:'方法並調用mutableCopy'。 – rmaddy

回答

3

使用dispatch_sync就可以了,只要您包裝所有陣列的讀寫操作並確保它是串行隊列即可。

但是,你可以通過允許併發讀取來改進。爲此,請在所有陣列讀取周圍使用dispatch_sync,並在所有陣列寫入周圍使用dispatch_barrier_sync。並設置隊列爲併發。

這樣做是否確保一次只能進行一次寫操作,讀操作將被阻塞直到寫操作完成,並且寫操作將一直等到所有當前讀操作完成。

+0

謝謝。我也會使用屏障去除物體,對嗎? – magiclantern

+0

是的,因爲刪除被認爲是「寫入」。任何改變陣列內容的東西都是「寫入」,需要使用屏障同步。 – rmaddy

+2

從技術上講,對於只讀操作,「NSMutableArray」也不是線程安全的。除非文檔另有明確說明,否則您不能假設線程安全。 (不過,我確定它實際上在讀取操作期間實現爲線程安全)。這可能需要在文檔中進行說明。 – bbum

0

使用GCD是正確的選擇。唯一的「難題」是你需要對該隊列執行所有操作:添加,刪除,插入等。

我還會提到你需要確保你不使用併發隊列。你應該使用一個串行隊列,無論如何這是默認的。

1

使用GCD併發隊列併爲陣列提供排序訪問器,您可以在讀寫時使用dispatch_sync同時讀取和dispatch_barrier_async同步讀寫。

- (id)methodToRead { 
    id __block obj = nil; 
    dispatch_sync(syncQueue, ^{ 
    obj = <#read_Something#>; 
    }); 
    return obj; 
} 

- (void) methodsForWriting:(id)obj { 
    dispatch_barrier_async(syncQueue, ^{ 
    // write passing obj to something 
    }); 
} 

這將保證期間寫的一切是從讀鎖定。

+0

不應該是'dispatch_barrier_sync'寫作嗎? –

+0

取決於,_async表示方法在塊執行之前返回。但塊執行順序應由同步隊列本身保證。當然這聽起來更合適。 – Andrea