1

我做的一件事是:

-(void)GrabbingProcess:(void (^)())block;
{
    self.OtherGrabbingIndicator +=1;
    block();
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        self.OtherGrabbingIndicator -=1;
    });
}

每次我想在后台运行可能需要很长时间的东西时,我都会做类似的事情

[Grabclass grab] GrabbingProcess: ^{ //做一些事情抓取数据等 }];

有许多这样的功能和许多这样的数据。例如,起初我会获取所有企业 ID。然后我会在单独的线程上获取有关业务的所有详细信息。

我想知道所有这些线程何时完成并发布合适的通知。

我的解决方案的问题是,一段时间后,self.OtherGrabbingIndicator 的值通常会徘徊在 2 或 3 左右,即使所有这些线程都已完成,也永远不会下降。

不知何故有些 self.OtherGrabbingIndicator +=1; “泄露”并且与 self.OtherGrabbingIndicator -=1 不匹配。我想知道这种泄漏怎么会发生?

4

1 回答 1

1

如果您想异步运行块,然后找出它们何时完成,则合适的工具是dispatch_group. 您可以使用 将块分派到特定的组和队列中dispatch_group_async(),该组将跟踪块何时完成。然后,您可以在组上同步等待完成dispatch_group_wait()或注册一个块以在组完成时调用dispatch_group_notify()


上述解决方案不起作用的原因是因为您没有以线程安全的方式访问/更改计数器。以下是会导致问题的一系列微不足道的事件:

开始:self.OtherGrabbingIndicator 为 1
线程 A:读取 self.OtherGrabbingIndicator
线程 B:读取 self.OtherGrabbingIndicator
线程 A:增加读取值并写回 self.OtherGrabbingIndicator
线程 B:增加读取值并写回 self.OtherGrabbingIndicator
End : self.OtherGrabbingIndicator 为 2

即使两个线程试图增加它,只有一个“成功”,你最终失去了另一个增量。这也可能在递减期间发生。如果您使用调度组,这个问题就会消失。


作为旁注,您永远不应该使用dispatch_get_current_queue(). 这是一个永远不应该在实际代码中使用的调试功能。主要原因是因为您不只是在一个队列上运行,而是同时在整个队列层次结构上运行,但此功能只能告诉您一个队列。此外,您可能正在某人的私人队列上运行,您当然不应该自己分派到该队列上。

于 2012-06-05T08:07:44.793 回答