我需要保护我的代码的关键区域,这是一个多线程的。我希望防止在其他线程完成之前多次调用它。这就是我正在使用的:
- (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
,如果此代码被调用两次,则会因为removeAllObjects
在开始时崩溃。
我仍然需要在另一个线程中调用internal...
方法,因为我不想阻止UI。那么在dispatch_async
调用尚未完成时阻止此方法启动的最佳方法是什么?
答案 0 :(得分: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];
}
});
这假设filterMainQueue
是 serial 。将dispatch_async
用于临界区可确保不会阻止主线程。另请注意"Dispatch Queues and Thread Safety"中的警告:
不要从传递给函数调用的同一队列上执行的任务中调用
dispatch_sync
函数。这样做会使队列死锁。
虽然internal...
方法会导致再次调用此方法,但这只会是一个问题。