2012-03-21 2 views
0

Я использовал Multithreading некоторое время, я думал, что получил его, но теперь моя программа рушится.object-c Как предотвратить действие во время выполнения потока

У меня есть метод, который должен загрузить данные для памяти сервера и доступа в зависимости от данных, этот процесс занимает много времени, поэтому я исполню ее из вторичных потоков, как это:

-(void)showPeople{ 
    dispatch_queue_t pintaOcupantes = dispatch_queue_create("Pinta Ocupantes", NULL); 
    dispatch_async(pintaOcupantes, ^{ 
    //BUNCH OF CODE 
    [self isPersonIn:jid]; 
    //MORE CODE that include methods calling isPersonIn 

}); 

Внутри этого блока есть isPersonIn. Он сбой, если я нажимаю слишком быстро кнопку, которая выполняет showPeople. IsPersonIn что-то вроде:

-(int)isPersonIn:(XMPPJID *)jid{ 
    int i = 0; 
    for(NSDictionary *card in self.listaGente){ 
     NSLog(@"la jid es: %@", [card objectForKey:@"jid"]); 
     NSLog(@"la jid del usuario es: %@", jid.user); 
     if([[card objectForKey:@"jid"] isEqualToString:jid.user]){ 
      return i; 
     } 
     i++; 
    } 
    return -1; 
} 

Он сравнивает XMPPJID с массивом, который является переменной экземпляра. isPersonIn вызывается несколько раз из разных методов, но все методы, которые его называют, принадлежат блоку, поэтому, насколько я понимаю, все исполнения isPersonIn должны быть сериализованы, FIFO, правильно?

Но если я нажму кнопку, которая выполняет showPeople, тот, который содержит блок, много раз очень быстро, приложение падает на isPersonIn, иногда без какого-либо сообщения. Я вижу потоки, когда он падает, и я вижу по крайней мере 2 потока с isPersonIn последним в стеке, что не имеет смысла, так как блок должен выполняться по одному, а не несколько потоков одновременно, не так ли?

Любая помощь будет очень восприимчивой.

Спасибо!

[EDIT] Также массив экземпляров, self.listaGente, изменяется вне блока.

ответ

1

Я не эксперт GCD, но я подозреваю, что причина, по которой вы получаете несколько потоков, заключается в том, что вы создаете новую очередь отправки каждый раз, когда вызывается showPeople.

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

[EDIT] Если коллекция изменена вне блока, но во время выполнения блока это может стать источником вашего сбоя. Из Fast Enumeration Documentation:

Перечня является «безопасным» -The переписчик имеет мутацию охрану, так что , если вы пытаетесь изменить коллекцию при перечислении, возникает исключение.

+0

Im не эксперт либо, но то, что я знаю, что блокирует любые другой поток для входа, пока текущая очередь, которая была создана, не завершила выполнение блока. Итак, новая очередь не создается до тех пор, пока предыдущая не закончится, Im прямо на этих парней? – subharb

+1

Я только что проверил документацию и нашел это: «Блоки, отправленные в последовательную очередь, выполняются по одному в порядке FIFO.Однако обратите внимание, что блоки, отправленные в независимые очереди, могут выполняться одновременно друг с другом. «Поэтому я думаю, что это говорит о том, что FIFO гарантируется только в одной очереди. https://developer.apple.com/library /mac/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/doc/uid/TP40008079-CH2-SW14 – KazR

+0

@KazR является правильным. Выполнение блока - это FIFO только в отношении очереди последовательной отправки, в которой они выполняются Поскольку вы создаете новую очередь каждый раз, когда вызывается showPeople, каждый блок запускается в собственной очереди отправки. Обратите внимание, что имя «Pinta Ocupantes» просто для удобства при отладке и фактически не заставляет очереди быть одинаковыми. Кроме того, вы теряете память здесь, потому что очереди отправки должны быть вручную выпущены и не обрабатываются ARC. – UIAdam

0

В этом случае защита массива, вызвавшего мое приложение для сбоя, устраняет проблему.

с помощью:

@syncronized(theArray){ 
    //CODE THAT WILL ACCESS OR WRITE IN THE ARRAY 
} 

Таким образом, потоки остановится раньше, если есть поток уже выполняет этот код, как мьютекс или семафор