iOS确保每个会话只调用一次函数

时间:2012-03-15 23:42:25

标签: ios multithreading thread-safety grand-central-dispatch

我有几个线程,一旦完成工作,我需要在每个操作中调用一次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();
}

另外,根据调用worker的方式,我不直接调用它们,而是将它们作为参数传递给函数。

3 个答案:

答案 0 :(得分: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 :(得分:1)

这听起来很乱,水平很低。您是否查看了Operation Queues中讨论的Concurrency Programming Guide和调度组和信号量。我认为他们可能会为您的问题提供更简单的解决方案。

答案 2 :(得分: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);

在所有先前提交的块完成执行之后执行屏障块,并且在屏障块之后提交的任何块将被强制等待直到屏障块完成。同样,由于显而易见的原因,您不能在全局队列上使用障碍块。您必须创建自己的并发队列。