保护关键代码不被再次调用

Z S*_*Z S 2 cocoa locking objective-c blocking grand-central-dispatch

我需要保护我的代码的关键区域,这是一个多线程.我希望防止在其他线程完成之前多次调用它.这就是我正在使用的:

- (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];
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

由于该internal_filterAllEventsIntoDictionary方法也可以访问self.sortedKeys,如果此代码被调用两次,它会因为removeAllObjects在开始时崩溃.

我仍然需要internal...在另一个线程中调用该方法,因为我不想阻止UI.那么,在dispatch_async呼叫仍未完成的情况下阻止此方法启动的最佳方法是什么?

Jos*_*ell 7

虽然我不是一个并发专家,但听起来你需要锁定你的sortedKeys对象.但是,如果你使用传统的锁,你最终会阻止主线程.

在Grand Central Dispatch世界中推荐的锁替换是将关键的代码段放在串行队列中.请参阅"并发编程指南"中的"消除基于锁的代码".

如果您将[self.sortedKeys removeAllObjects];调用放在同一个队列internal...上,并且调度了带有调用的块,则可以保证在该块完成之后它才会发生:

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

这假定filterMainQueue串行的.使用dispatch_async临界区保证了主线程不会被阻塞.另请注意"Dispatch Queues and Thread Safety"中的警告:

不要dispatch_sync从传递给函数调用的同一队列上执行的任务调用该函数.这样做会使队列死锁.

虽然这只是一个问题,如果该internal...方法执行的操作会导致再次调用此方法.