2013-06-29 31 views
1

當NSOperation子類化完成一小部分工作時,我發現它很容易陷入僵局。下面我有一個玩具的例子,很容易理解爲什麼它永遠不會完成。異步可可 - 在NSOperation中防止「簡單」(明顯)死鎖?

我似乎只能通過解決方案來防止來自主叫方的死鎖,而不是被叫方。例如,調用者可以繼續運行運行循環,而不是等待結束等。如果主線程在操作期間需要同步消息,那麼我想知道是否存在操作子類可以實現的規範解決方案防止這種類型的死鎖。我纔剛剛開始沾我的腳趾在異步編程...

@interface ToyOperation : NSOperation 

@end 

@implementation ToyOperation 

- (void)main 
{ 
    // Lots of work 

    NSString *string = @"Important Message"; 
    [self performSelector:@selector(sendMainThreadSensitiveMessage:) onThread:[NSThread mainThread] withObject:string waitUntilDone:YES]; 

    // Lots more work 
} 

- (void)sendMainThreadSensitiveMessage:(NSString *)string 
{ 
    // Update the UI or something that requires the main thread... 
} 

@end 

- (int)main 
{ 
    ToyOperation *op = [[ToyOperation alloc] init]; 
    NSOperationQueue *opQ = [[NSOperationQueue alloc] init]; 
    [opQ addOperations: @[ op ] waitUntilFinished:YES]; // Deadlock 

    return; 
} 

回答

3

如果主線程 操作過程中需要是同步的消息,我想知道如果有一個規範的解決方案,一個 操作子類可以實現以防止這種類型的 死鎖。

有。 切勿對主隊列進行同步呼叫。後續操作:不要在主隊列中進行同步呼叫。而且,實際上,它可以概括爲永遠不要進行從任何隊列到任何其他隊列的同步呼叫。

通過這樣做,可以保證主隊列不被阻塞。當然,可能有一個例外情況誘使你違反這一規定,甚至是真正無法避免的情況。但是這應該是個例外,因爲即使是一個dispatch_sync()(或NSOpQueue waitUntilDone)也有可能發生死鎖。

當然,從隊列到隊列的數據更新可能會非常棘手。有幾種選擇;一個併發安全數據層(非常困難),只傳遞不可變對象或數據的副本(通常是爲了顯示目的而向主隊列傳遞 - 很簡單,但可能很昂貴),或者你可以沿着基於UUID的錯誤模型核心數據使用。不管你如何解決這個問題,與任何其他併發模型相比,這個問題都不是什麼新鮮事。

一個例外是用隊列更換時鎖(例如,而不是使用@synchronized()內部的一類,使用串行GCD隊列,並使用dispatch_sync()到該隊列的任何地方,一個同步操作必須發生。更快,更直接)。但是,這不是解決完全不同的問題的例外。