5

The test code is as followed:

dispatch_queue_t queue = dispatch_queue_create("sc", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
    [NSThread sleepForTimeInterval:10];
    NSLog(@"10s --- %@", [NSThread currentThread]);
});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), queue, ^{
    NSLog(@"First: 5s --- %@", [NSThread currentThread]);
});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), queue, ^{
    NSLog(@"Second: 5s --- %@", [NSThread currentThread]);
});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), queue, ^{
    NSLog(@"Third: 5s --- %@", [NSThread currentThread]);
});

Here I created a concurrent queue, and sleep one thread using async way.

However, the output is:

2016-03-26 12:17:57.164 TestPlayground[28188:551287] 10s --- <NSThread: 0x7fa080511730>{number = 2, name = (null)}
2016-03-26 12:17:57.165 TestPlayground[28188:551287] First: 5s --- <NSThread: 0x7fa080511730>{number = 2, name = (null)}
2016-03-26 12:17:57.166 TestPlayground[28188:551307] Second: 5s --- <NSThread: 0x7fa080704a80>{number = 3, name = (null)}
2016-03-26 12:17:57.166 TestPlayground[28188:551301] Third: 5s --- <NSThread: 0x7fa080511530>{number = 4, name = (null)}

It seems that GCD block first thread for 10 seconds and then it start to create new thread for concurrent works.

But if I just replace the self created queue with global concurrent queue and do not change the following job

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// ... same as before

The output is more reasonable

2016-03-26 12:23:29.496 TestPlayground[28320:558467] First: 5s --- <NSThread: 0x7ff473c08b80>{number = 4, name = (null)}
2016-03-26 12:23:29.496 TestPlayground[28320:558483] Second: 5s --- <NSThread: 0x7ff473f18c50>{number = 2, name = (null)}
2016-03-26 12:23:29.496 TestPlayground[28320:558471] Third: 5s --- <NSThread: 0x7ff473d0a7c0>{number = 3, name = (null)}
2016-03-26 12:23:34.030 TestPlayground[28320:558456] 10s --- <NSThread: 0x7ff473e218e0>{number = 5, name = (null)}

What's the dispatch rule in GCD for this kind of jobs? And why the self created concurrent queue differ with global queue?


If I add a new job before sleep job

dispatch_queue_t queue = dispatch_queue_create("sc", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{ NSLog(@"start --- %@", [NSThread currentThread]); });

dispatch_async(queue, ^{
    [NSThread sleepForTimeInterval:10];
    NSLog(@"10s --- %@", [NSThread currentThread]);
});
// ... same as before

The output is

2016-03-26 12:44:25.728 TestPlayground[28616:571502] start --- <NSThread: 0x7fb7c1604250>{number = 2, name = (null)}
2016-03-26 12:44:35.733 TestPlayground[28616:571511] 10s --- <NSThread: 0x7fb7c1422e40>{number = 3, name = (null)}
2016-03-26 12:44:35.734 TestPlayground[28616:571517] First: 5s --- <NSThread: 0x7fb7c16032d0>{number = 4, name = (null)}
2016-03-26 12:44:35.734 TestPlayground[28616:571511] Second: 5s --- <NSThread: 0x7fb7c1422e40>{number = 3, name = (null)}
2016-03-26 12:44:35.734 TestPlayground[28616:571552] Third: 5s --- <NSThread: 0x7fb7c1608950>{number = 5, name = (null)}
xi.lin
  • 3,326
  • 2
  • 31
  • 57
  • As a test, call `dispatch_async(queue, ^{ NSLog(@"start --- %@", [NSThread currentThread]); });` before the call to `dispatch_async` containing the sleep. What affect did that have? – rmaddy Mar 26 '16 at 04:43
  • @rmaddy I've updated the post with output. It seems that it just use new thread for the job. – xi.lin Mar 26 '16 at 04:47
  • @xi.lin Yeah-- this is bizarre. I'll ask the dispatch team about this behavior and, if I get the chance, pull the source and debug it myself as I'm quite curious. – bbum Mar 26 '16 at 17:51

1 Answers1

3

Consider the output of the following:

00:53:38.852 asdfasdfasdf[11650:2114104] start
00:53:38.854 asdfasdfasdf[11650:2114104] main <NSThread: 0x100206110>{number = 1, name = main}
00:53:38.854 asdfasdfasdf[11650:2114126] Enter sleep block
00:53:38.854 asdfasdfasdf[11650:2114127] bare async
00:53:48.858 asdfasdfasdf[11650:2114126] Sleep block done (10 seconds).
00:53:48.859 asdfasdfasdf[11650:2114126] dispatch_after() 5 --- <NSThread: 0x10020aa00>{number = 2, name = (null)}

So, the sleeping thread doesn't block the invocation of asynchronously queued blocks (even with a thread sleep thrown in), but it does block the execution of dispatch_after().

Which leaves me confused. rdar://25373048

    dispatch_queue_t queue = dispatch_queue_create("sc", DISPATCH_QUEUE_CONCURRENT);

    NSLog(@"start");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"main %@", [NSThread currentThread]);

        dispatch_async(queue, ^{
            NSLog(@"Enter sleep block");
            [NSThread sleepForTimeInterval:10];
            NSLog(@"Sleep block done (10 seconds).");
        });

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), queue, ^{
            NSLog(@"dispatch_after() 5 --- %@", [NSThread currentThread]);
        });

        dispatch_async(queue, ^{
            NSLog(@"bare async");
        });
    });

    [[NSRunLoop currentRunLoop] run];
bbum
  • 162,346
  • 23
  • 271
  • 359
  • Yes, it did seems that `dispatch_after` is different from `dispatch_async`. And it seems that the global concurrent queue has some special strategies. – xi.lin Mar 26 '16 at 12:10
  • @xi.lin it is a bug in dispatch that will be fixed in some future release (no idea when). For now, I'd suggest using dispatch_after against the global queue and then dispatch_async to your target queue, if you really need that pattern. – bbum Mar 27 '16 at 00:33
  • So your radar is confirmed by the developer team now? Thanks for the information. Last night, I tried to read the source code of libdispatch, but I haven't found the reason yet. – xi.lin Mar 27 '16 at 03:17
  • @xi.lin Yes-- known issue. I was able to build and run with a debug build of lib dispatch, but the introspection stuff gets in the way and I wasn't actually able to debug through dispatch. Looking at the state it gets wedged in, the interaction is a bit subtle. – bbum Mar 27 '16 at 17:13
  • Thanks for your help – xi.lin Mar 27 '16 at 18:29