关于块捕获值和 dispatch_async 的有趣事情
Interesting thing about block captured value and dispatch_async
今天,当我用 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
I have tried many times, even the third block finished firstly, the value of temp
is 2
, before the ++
executed. Shouldn't it be 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,
有人知道这件事吗?
谢谢,
defaultBackgroundQueue
是并发的,所以你不应该依赖执行顺序。很可能 temp++
已经执行,但来自另一个块的 NSLog
没有。如果您想要不同的行为,请使用串行调度队列。
这里发生的事情如下:
异步线程确实以不同于您在 print/log 语句中看到的顺序完成,这意味着 NSLog
语句执行 after 任何同时已经设法对(共享)基础值 temp
进行计算的其他线程(这可能是由于 NSLog
语句需要(相当)更多的时间才能完成来自其他线程的简单计算完成)。
Boris 也有一个正确的观点,显然,线程确实并发执行,我相信您已经意识到这一点,但它并不总是一开始就那么明显。
我把NSLog
改成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
正如@the_critic所说,NSLog
并不是实际结果。
谢谢,
今天,当我用 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
I have tried many times, even the third block finished firstly, the value of
temp
is2
, before the++
executed. Shouldn't it be1
?
我使用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, 有人知道这件事吗? 谢谢,
defaultBackgroundQueue
是并发的,所以你不应该依赖执行顺序。很可能 temp++
已经执行,但来自另一个块的 NSLog
没有。如果您想要不同的行为,请使用串行调度队列。
这里发生的事情如下:
异步线程确实以不同于您在 print/log 语句中看到的顺序完成,这意味着 NSLog
语句执行 after 任何同时已经设法对(共享)基础值 temp
进行计算的其他线程(这可能是由于 NSLog
语句需要(相当)更多的时间才能完成来自其他线程的简单计算完成)。
Boris 也有一个正确的观点,显然,线程确实并发执行,我相信您已经意识到这一点,但它并不总是一开始就那么明显。
我把NSLog
改成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
正如@the_critic所说,NSLog
并不是实际结果。
谢谢,