【问题标题】:iOS Ensuring a Function Is Called Only Once Per SessioniOS确保每个会话只调用一次函数
【发布时间】:2012-03-15 23:42:24
【问题描述】:

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

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

【问题讨论】:

  • 为什么上面的方法不起作用?我觉得还可以。

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


【解决方案1】:

您想使用调度组。首先创建一个组,安排组中的三个工作人员,然后向组中添加一个通知块。 它应该看起来像这样:

//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。

【讨论】:

    【解决方案2】:

    这听起来非常混乱和低级。您是否查看过Operation QueuesConcurrency Programming Guide 中讨论的调度组和信号量。我认为他们可能会为您的问题提供更简单的解决方案。

    【讨论】:

    • 确实像drekka说的,如果你使用grand central dispatch group的功能,当组内所有的任务都完成后,会有一个选项来执行。
    • 我已经阅读了那些文档。我正在考虑实际使用条件互斥锁。我不确定操作队列是否会有所帮助,因为我正在调用像 [Object doSomethingWithBlock:^{}] 这样的工作人员,它将异步执行传入的块。
    【解决方案3】:

    如果您的目标是 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);
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-12
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      相关资源
      最近更新 更多