0

У меня есть несколько потоков, и как только все они закончены, мне нужно вызвать метод myMergeBlock ровно один раз за действие. Я не могу использовать dispatch_once, потому что я хочу, чтобы иметь возможность позвонить myMergeBlock в более позднее время.iOS Обеспечение функции вызывается только один раз за сеанс

Некоторые псевдо-код выглядит следующим образом, но еще не поточно:

BOOL worker1Finished, worker2Finished, worker3Finished; 

void (^mergeBlock)(void) = ^{ 
    if (worker1Finished && worker2Finished && worker3Finished) 
     dispatch_async(queue, myMergeBlock); // Must dispatch this only once 
} 

void (^worker1)(void) = ^{ 
    ... 
    worker1Finished = YES; 
    mergeBlock(); 
} 

void (^worker2)(void) = ^{ 
    ... 
    worker2Finished = YES; 
    mergeBlock(); 
} 

void (^worker3)(void) = ^{ 
    ... 
    worker3Finished = YES; 
    mergeBlock(); 
} 

Кроме того, на основе, как рабочие называются, я не называю их непосредственно, но вместо того, чтобы передать их в функцию как аргументы.

+0

Почему это не работает? Кажется, все в порядке. – CodaFi

ответ

3

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

//create dispatch group 
dispatch_group_t myWorkGroup = dispatch_group_create(); 

//get one of the global concurrent queues 
dispatch_queue_t myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL); 

//submit your work blocks 
dispatch_group_async(myWorkGroup, myQueue, worker1); 
dispatch_group_async(myWorkGroup, myQueue, worker2); 
dispatch_group_async(myWorkGroup, myQueue, worker3); 

//set the mergeBlock to be submitted when all the blocks in the group are completed 
dispatch_group_notify(myWorkGroup, myQueue, mergeBlock); 

//release the group as you no longer need it 
dispatch_release(myWorkGroup); 

Вы могли бы повесить на группе и повторно использовать его в дальнейшем, если вы предпочитаете. Обязательно планируйте работу перед уведомлением. Если вы попытаетесь сначала запланировать уведомление, оно будет отправлено немедленно.

Я не тестировал этот код, но я использую dispatch_groups в своих проектах.

1

Звучит очень грязно и низко. Вы просмотрели Operation Queues и группы отправки и семафоры, как обсуждалось в Concurrency Programming Guide. Я думаю, они могут предложить более простые решения вашей проблемы.

+0

Действительно, как говорит дрекка, если вы используете функцию центральной центральной группы отправки, есть возможность выполнить что-то, когда все задачи в группе будут завершены. – Pochi

+0

Я прочитал эти документы. Я думал об использовании условных мьютексов. Я не уверен, что очереди операций помогут, потому что я вызываю таких рабочих, как '[Object doSomethingWithBlock:^{}]', который будет выполнять асинхронно переданный в блоке. – Dex

0

Если вы ориентируетесь на Lion или iOS 5 и выше, вы можете использовать barrier blocks, пока блоки отправляются в неглобальной параллельной очереди. Например:

dispatch_queue_t customConcurrentQueue = dispatch_queue_create("customQueue", DISPATCH_QUEUE_CONCURRENT); 
dispatch_async(customConcurrentQueue, worker1); 
dispatch_async(customConcurrentQueue, worker2); 
dispatch_async(customConcurrentQueue, worker3); 
dispatch_barrier_async(customConcurrentQueue, mergeBlock); 

//Some time later, after you're sure all of the blocks have executed. 
dispatch_queue_release(customConcurrentQueue); 

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

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