iOS гарантирует, что функция вызывается только один раз за сеанс - PullRequest
0 голосов
/ 16 марта 2012

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

Некоторый псевдокод выглядит так, но еще не безопасен для потоков:

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();
}

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

Ответы [ 3 ]

3 голосов
/ 12 апреля 2012

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

//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 голос
/ 16 марта 2012

Это звучит очень грязно и низкий уровень.Рассматривали ли вы Очереди операций и Группы рассылки и семафоры, как описано в Руководстве по программированию параллелизма .Я думаю, что они могут предложить более простые решения вашей проблемы.

0 голосов
/ 16 апреля 2012

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

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);

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

...