有关块捕获值和dispatch_async的有趣信息

时间:2016-02-29 13:59:10

标签: ios objective-c block

今天当我使用dispatch_async测试一些代码时,我发现了一个有趣的事情,当我运行这样的代码时:

static int temp = 1;
    dispatch_queue_t defaultBackgroundQueue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
dispatch_async(defaultBackgroundQueue, ^{
        NSLog(@"blk 0 :%d", temp);
    });
    dispatch_async(defaultBackgroundQueue, ^{
        NSLog(@"blk 1 :%d", temp++);
    });
    dispatch_async(defaultBackgroundQueue, ^{
        NSLog(@"blk 2 :%d", temp);
    });

猜猜日志是什么?这很有趣,像这样:

2016-02-29 21:39:40.700 GCDDemo[46594:3826498] blk 2 :2
2016-02-29 21:39:40.700 GCDDemo[46594:3826496] blk 1 :1
2016-02-29 21:39:40.696 GCDDemo[46594:3826495] blk 0 :1
  

temp执行之前,我已尝试多次,即使第三个块首先完成,2的值为++。不应该是1

使用clang将代码转换为C ++后,没有什么特别的关键代码:

static void __main_block_func_1(struct __main_block_impl_1 *__cself) {
int *temp = __cself->temp; // bound by copy
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_s6_v33rqm893pddvmp9w2hyfhtc0000gn_T_main_d902a1_mi_1, (*temp)++);
    } 

static int temp = 1;
dispatch_queue_t defaultBackgroundQueue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
dispatch_async(defaultBackgroundQueue, ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &temp)));
dispatch_async(defaultBackgroundQueue, ((void (*)())&__main_block_impl_1((void *)__main_block_func_1, &__main_block_desc_1_DATA, &temp)));
dispatch_async(defaultBackgroundQueue, ((void (*)())&__main_block_impl_2((void *)__main_block_func_2, &__main_block_desc_2_DATA, &temp)));

你可以自己尝试一下,我在我的Mac book pro,OS X 10.11上进行了测试, 有人知道这个吗? 谢谢,

3 个答案:

答案 0 :(得分:1)

这里会发生以下情况:

异步线程的完成顺序与您在print / log语句中看到的顺序不同,这意味着console.log(get_socketId("irc.freenode.com", 6667)); 语句在任何其他线程之后执行设法对(共享)基础值NSLog进行计算(这可能是因为temp语句需要(相当多)在完成其他任何简单计算之前完成的时间。线程完成)。

鲍里斯也有一个有效的观点,显然,线程确实同时执行,我相信你已经意识到这一点,但首先并不总是那么明显。

答案 1 :(得分:0)

defaultBackgroundQueue是并发的,因此您不应该按执行顺序进行中继。很可能,temp++已经执行,但来自另一个区块的NSLog不是。如果您想要不同的行为,请使用串行调度队列。

答案 2 :(得分:0)

printf更改为sleep后,添加dispatch_async(defaultBackgroundQueue, ^{ sleep(1); printf("blk 0:%d\n", temp); }); dispatch_async(defaultBackgroundQueue, ^{ sleep(1); printf("blk 1:%d\n", temp++); }); dispatch_async(defaultBackgroundQueue, ^{ sleep(1); printf("blk 2:%d\n", temp); }); dispatch_async(defaultBackgroundQueue, ^{ sleep(1); printf("blk 3:%d\n", temp); });

blk 1:1
blk 0:2
blk 2:2
blk 3:2

结果发生了变化:

NSLog

正如@the_critic所说,echo $elem["Reference"]; echo $elem["Key"]; 并不代表实际结果。

谢谢,