Защита критического кода от повторного вызова - PullRequest
2 голосов
/ 17 ноября 2011

Мне нужно защитить критическую область моего кода, которая является многопоточной. Я хочу, чтобы он не вызывался несколько раз, пока не закончится другой поток. Вот с чем я работаю:

- (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... в другом потоке, поскольку я не хочу блокировать пользовательский интерфейс. Итак, как лучше всего блокировать запуск этого метода, пока вызов dispatch_async еще не завершен?

1 Ответ

7 голосов
/ 17 ноября 2011

Хотя я далеко не эксперт по параллелизму, для меня это звучит так, будто вам нужен замок на вашем sortedKeys объекте.Однако если бы вы использовали традиционную блокировку, вы бы в конечном итоге заблокировали основной поток.

Рекомендуемая замена блокировок в мире Grand Central Dispatch - поместить критические участки кода в последовательную очередь.См. «Устранение кода на основе блокировки» в Руководстве по программированию параллелизма.

Если вы поместите вызов [self.sortedKeys removeAllObjects]; в ту же очередь, в которой запланирован блок с вызовом internal..., вы гарантируете, что этого не произойдет, пока этот блок не завершится:

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

Предполагается, что filterMainQueue это serial .Использование dispatch_async для критической секции гарантирует, что основной поток не будет заблокирован.Также обратите внимание на предупреждение в «Очереди отправки и безопасность потока» :

Не вызывайте функцию dispatch_sync из задачи, которая выполняется в той же очереди, которую вы передаетеВаш вызов функции.Это приведет к блокировке очереди.

Хотя это будет проблемой, только если метод internal... сделает что-то, что вызовет этот метод снова.

...