4
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];
 }

安慰 :

   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 循环同时/并行 执行,这可以解释为什么 while 循环需要多一个周期才能确认更新的条件?

4

2 回答 2

1

是的,它正在同时运行。这意味着您的块可以在 while 循环期间的任何给定时刻执行,例如在通过条件之后,但在增加全局之前,或者在增加全局之后。如果您多次运行代码,您会注意到有时total计数匹配,有时则不匹配。(编辑:这意味着您的代码在同时运行时是“不确定的”。)

如果您尝试在串行队列中运行上述代码,则 while 循环将无限运行,并且不会打印任何总数。在串行队列中,您在 callDispatch 中安排的块确实会添加到队列中以供下一个调用,但鉴于无限循环永远不会退出,该队列中的任何其他内容都不会被调用。

Apple Doc 中的更多信息:GCD 提供三种不同类型的队列

于 2012-08-02T21:23:17.993 回答
0

鉴于您有效地锁定了主事件循环,那么正在执行块的队列不能是主队列。

因此,您肯定有两个线程在运行,因此,并不能真正保证在第一个块和第二个块执行之间可能经过多少时间。同样,如果 dispatch_get_current_queue() 碰巧检索到一个异步队列,您不能假设其中的任何块同时执行。

或者,更坦率地说:你无法推理并发代码中的执行和调度模式;你不能“玩电脑”,只能想出一种情况下发生的近似值。

于 2012-08-02T20:58:35.160 回答