2012-06-05 43 views
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抢] GrabbingProcess:^ { //做一些抓取数据等。 }];

有许多这样的功能和许多这样的数据。例如,起初我会抓住所有的企业ID。然后,我会在单独的主题上抓住所有业务细节。

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

我的解决方案的问题是,一段时间后,往往self.OtherGrabbingIndicator值徘徊在2或3从不下去,即使所有的线程已经完成。

不知何故一些self.OtherGrabbingIndicator + = 1; “泄漏”并且与自身不匹配。其他抓取指示符 - = 1。我想知道这种泄漏怎么会发生?

+1

永远不会*使用'dispatch_get_current_queue()'。这是一个调试功能,不适合在代码中使用。 –

+1

谢谢。你能参考吗? –

+0

请参阅联机帮助页。在“CAVEATS”下它说这个函数只用于调试/日志记录的目的。更具体地说,该函数只返回当前队列层次结构的顶端,这可能是别人的私有队列。 –

回答

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
结束:self.OtherGrabbingIndicator是2

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


作为一个侧面说明,你不应该使用dispatch_get_current_queue()。这是一个调试功能,绝对不应该在实际代码中使用。主要原因是因为你不只是在一个队列上运行,而是同时运行在一个整体层次上的队列中,但是这个函数只能告诉你关于这个队列的信息。另外,你可能在某人的私人队列中跑步,你当然不应该亲自调度。

+0

谢谢。使用dipatch_group是要走的路。顺便说一下自己。其他捕食指示器是原子的。 –

+0

@JimThio:该属性可能是原子的,但只包含一次读取或一次写入。您的代码正在执行读取+写入操作,在属性级别上该操作不可能是原子级的。您需要更高级别的同步才能执行此操作(例如,使用锁定或调度队列对属性进行门户访问)。 –

相关问题