int total = 0; // these are globals..
BOOL dispatchCalled = NO; //
-(void) callDispatch
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
dispatchCalled = YES;
NSLog(@"Total, after 300ms, is %i", total);
});
}
-(void)play // this is my "main" method..
{
NSLog(@"app starts running");
[self callDispatch];
while(!dispatchCalled)
{
total++;
}
[self callDispatch];
}
console:
2012-08-02 20:36:05.357 MyProject[8245:1a07] app starts running
2012-08-02 20:36:05.693 MyProject[8245:3d03] Total, after 300ms, is 11513522
2012-08-02 20:36:05.993 MyProject[8245:3d03] Total, after 300ms, is 11513523
当第一次执行callDispatch中包含的方法时,while循环有时间执行11513522次。此时,while循环的条件设置为YES
,而while循环不应再执行。但是,它在通过调度方法条件确认更新之前再执行一次。那是为什么?
是因为callDispatch中包含的方法将与 while循环一起同时/并行 执行,这可以解释为什么需要再循环一次 - 循环以确认更新的条件?
答案 0 :(得分:1)
是的,它正在同时运行。这意味着您的块可以在while循环期间的任何给定时刻执行,例如在传递条件之后,但在递增全局之前,或者在递增全局之后。如果您多次运行代码,您会注意到total
计数有时会匹配,有时则不会。 (编辑:这意味着您的代码在并发运行时是“不确定的”。)
如果您尝试在串行队列中运行上述代码,则while循环无限运行,并且不会打印任何总计。在串行队列中,您在callDispatch DOES中调度的块被添加到要调用的队列中,但是如果无限循环永远不会退出,那么该队列中的任何其他内容都不会被调用。
Apple Doc中的更多信息:GCD offers three different kinds of queues
答案 1 :(得分:0)
鉴于您正在有效地锁定主事件循环,那么正在执行块的队列不能是主队列。
因此,你肯定有两个线程正在运行,因此,没有真正的保证在第一个块和第二个块执行之间可以传递多少时间。同样,如果dispatch_get_current_queue()恰好检索异步队列,则可以不假设其中任何块的同时执行。
或者,更坦率地说:你不能推断并发代码中的执行和调度模式;你不能玩电脑"除了近似于一种情况下发生的事情之外,我想出的任何东西。