2012-06-05 5 views
1

Единственное, что я делаю:Как узнать, закончилось ли задание, требующее многопоточности?

-(void)GrabbingProcess:(void (^)())block; 
{ 
    self.OtherGrabbingIndicator +=1; 
    block(); 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{ 
     self.OtherGrabbingIndicator -=1; 
    }); 
} 

Everytime Я хочу, чтобы запустить что-то, что может занять длительное время в фоновом режиме, я что-то вроде

[Grabclass грейфером] GrabbingProcess:^{ // Сделайте что-нибудь захват данных и т. Д. }];

Есть много таких функций и многие такие данные. Например, сначала я бы захватил все идентификаторы предприятий. Тогда я бы захватил все детали на предприятиях в отдельной теме.

Я хочу знать время, когда ВСЕ эти потоки закончили и разместит соответствующее уведомление.

Проблема с моим решением заключается в том, что через некоторое время, довольно часто значение self.OtherGrabbingIndicator вращается вокруг 2 или 3, никогда не спускаясь, хотя все эти потоки закончены.

Каким-то образом некоторые из себя. ДругГрабингИндикатор + = 1; «просочился» и не совпадал с самим собой. ДругГрабингИндикатор - = 1. Интересно, как эта утечка может произойти?

+1

Никогда * никогда * используйте 'dispatch_get_current_queue()'. Это функция отладки и не подходит для использования в коде. –

+1

Спасибо. Вы можете это сделать? –

+0

См. Справочную страницу. В разделе «CAVEATS» говорится, что эта функция предназначена только для целей отладки/ведения журнала. Более конкретно, эта функция возвращает только верхушку текущей иерархии очередей, которая может быть чужой частной очередью. –

ответ

1

Если вы хотите запустить блоки асинхронно, а затем узнать, когда они будут сделаны, соответствующий инструмент будет dispatch_group. Вы можете отправлять блоки по определенной группе и очереди с помощью dispatch_group_async(), и группа будет отслеживать, когда блок будет закончен. Затем вы можете либо ждать синхронно в группе, чтобы завершить с dispatch_group_wait(), либо зарегистрировать блок, который будет вызываться, когда группа будет выполнена с dispatch_group_notify().


Причина, почему ваше решение выше не работает, потому что вы не имеете доступ/мутируете счетчик в THREADSAFE образом. Вот тривиальный ряд событий, которые вызывают проблемы:

Начало: self.OtherGrabbingIndicator является 1
Поток А: читает self.OtherGrabbingIndicator
Thread B: читает self.OtherGrabbingIndicator
Thread A: увеличивает значение считывания и записывает обратно в self.OtherGrabbingIndicator
Thread B: увеличивает значение считывания и записывает обратно self.OtherGrabbingIndicator
End: self.OtherGrabbingIndicator 2

Даже если две нити пытались увеличить его, только один «удалось», и вы в конечном итоге потери другого приращения. Это может случиться и во время декремента. Если вы используете группы отправки, эта проблема исчезнет.

В качестве побочного примечания вы никогда не должны использовать dispatch_get_current_queue(). Это функция отладки, которая никогда не должна использоваться в реальном коде. Основная причина заключается в том, что вы не просто работаете в одной очереди, вы работаете одновременно с целой иерархией очередей, но эта функция может только сообщать вам об одной очереди. Кроме того, вы можете работать в чьей-то частной очереди, и вы, конечно же, не должны отправлять на нее себя.

+0

Спасибо. Использование dipatch_group - путь. Кстати, self.OtherGrabbingIndicator является атомарным. –

+0

@JimThio: свойство может быть атомарным, но оно охватывает только одно чтение или запись. Ваш код выполняет чтение + запись, которая не может быть атомарной на уровне свойства. Для этого вам нужна синхронизация на более высоком уровне (например, при закрытии доступа к объекту с блокировкой или очереди отправки). –

Смежные вопросы