Search code examples
iosobjective-cblock

Interesting thing about block captured value and dispatch_async


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 is 2, before the ++ executed. Shouldn't it be 1 ?

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,


Solution

  • 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.