2011-11-17 62 views
2

我需要保護我的代碼的關鍵區域,它是多線程的。我想阻止它在另一個線程完成之前被多次調用。這是我與合作:保護關鍵代碼不被再次調用

- (void) filterAllEventsIntoDictionary{ 

    // start critical area 
    if (self.sortedKeys.count != 0) { 
     [self.sortedKeys removeAllObjects]; 
    } 
    dispatch_async(self.filterMainQueue, ^{ 

     [self internal_filterAllEventsIntoDictionary]; 

     dispatch_sync(dispatch_get_main_queue(), ^{ 
      [self.tableView reloadData]; 
     }); 
    }); 
} 

由於internal_filterAllEventsIntoDictionary方法還訪問self.sortedKeys,如果這個代碼被調用了兩次,它在開始崩潰,因爲​​。

我還需要在另一個線程中調用internal...方法,因爲我不想阻塞UI。那麼在dispatch_async調用仍未完成時阻止此方法開始的最佳方法是什麼?

回答

7

儘管我不是一名併發性專家,但在我看來,您需要鎖定您的sortedKeys對象。不過,如果你使用傳統的鎖,你最終會阻止主線程。

在Grand Central Dispatch的世界中推薦使用的鎖具替代品是將關鍵代碼段放在串行隊列中。參見併發編程指南中的"Eliminating Lock-Based Code"

如果你把[self.sortedKeys removeAllObjects];調用到,隨着internal...調用的程序段被安排在同一個隊列,你能保證它不會發生,直到該節結束:

// start critical area 
dispatch_async(self.filterMainQueue, ^{ 
    if (self.sortedKeys.count != 0) { 
     [self.sortedKeys removeAllObjects]; 
    } 
}); 

這假定filterMainQueueserial。臨界區使用dispatch_async確保主線程不會被阻塞。另外要注意的預警"Dispatch Queues and Thread Safety"

不要從上您傳遞給你的函數調用相同的隊列執行任務調用dispatch_sync功能。這樣做會使隊列死鎖。

雖然這隻會是一個問題,如果internal...方法做一些事情,導致此方法被再次調用。

+0

感謝您指出正確的方向。 –