Reputation: 127
Today when I test some code with dispatch_async, I found a interesting thing, when I run some code like this:
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);
});
Guess what's the log is? It's very interesting, like this:
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
?
After I converted the code into C++ using clang
, nothing special, key code:
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)));
You can give it a try yourself, I tested it on my Mac book pro, OS X 10.11, Any one know something about this ? Thanks,
Upvotes: 1
Views: 90
Reputation: 127
After I change the NSLog
to printf
, and add a 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);
});
the result changed:
blk 1:1
blk 0:2
blk 2:2
blk 3:2
so as @the_critic said, NSLog
didn't mean the actually result.
Thanks,
Upvotes: 0
Reputation: 12820
What happens here is the following:
The asynchronous threads do complete in a different order than what you see in the the print/log statements meaning that the NSLog
statement executes after any of the other threads which meanwhile already did manage to do a computation on the (shared) underlying value temp
(this is probably due to the fact that the NSLog
statement takes (considerably) more time to finish before any of the simple calculations from the other threads finish).
Boris also has a valid point, obviously, the threads do execute concurrently, I'm sure you are aware of that, but it's not always as obvious in the first place.
Upvotes: 1
Reputation: 4268
defaultBackgroundQueue
is concurrent, so you shouldn't relay on execution order. It's quite possible, that temp++
is already executed, but NSLog
from another block is not. If you want different behavior, use serial dispatch queue.
Upvotes: 0