3

I have the following code:

- (void)test_with_running_runLoop {
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    NSTimeInterval checkEveryInterval = 0.05;

    NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue());

    dispatch_async(dispatch_get_main_queue(), ^{
        sleep(1);
        NSLog(@"I will reach here, because currentRunLoop is run");
        dispatch_semaphore_signal(semaphore);
    });

    while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW))
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:checkEveryInterval]];

    NSLog(@"I will see this, after dispatch_semaphore_signal is called");
}

- (void)test_without_running_runLoop {
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue());

    dispatch_async(dispatch_get_main_queue(), ^{
        sleep(1);
        NSLog(@"I will not reach here, because currentRunLoop is not run");
        dispatch_semaphore_signal(semaphore);
    });

    NSLog(@"I will just hang here...");
    while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW));

    NSLog(@"I will see this, after dispatch_semaphore_signal is called");
}

producing the following:

Starting CurrentTests/test_with_running_runLoop
2012-11-29 08:14:29.781 Tests[31139:1a603] Is main queue? : 1
2012-11-29 08:14:30.784 Tests[31139:1a603] I will reach here, because currentRunLoop is run
2012-11-29 08:14:30.791 Tests[31139:1a603] I will see this, after dispatch_semaphore_signal is called
OK (1.011s)

Starting CurrentTests/test_without_running_runLoop
2012-11-29 08:14:30.792 Tests[31139:1a603] Is main queue? : 1
2012-11-29 08:14:30.797 Tests[31139:1a603] I will just hang here...

My questions are related to each other:

  1. If I understand it right, main queue (dispatch_get_main_queue()) is a serial queue. I block the main queue/main thread with dispatch_semaphore_wait, so why do I see the "I will reach here, because currentRunLoop is run" in the first test case (I'm OK with the second case - in my understanding, it does, what it should)?

  2. How a serial queue, having current executing task blocked, can have a next task (oh, this mysterious runLoop:beforeDate:) dispatched before the current one is unlocked?

I want to hear detailed and comprehensive answer on this, because very, very much things (here around on SO too) depend on this issue!

UPDATE: Besides the accepted answer, this SO topic has good answer to this question: Pattern for unit testing async queue that calls main queue on completion

pkamb
  • 26,648
  • 20
  • 124
  • 157
Stanislav Pankevich
  • 9,838
  • 6
  • 60
  • 113

1 Answers1

6

Because the default runloop on the main thread has the special behaviour that, when run, it also processes for the main dispatch queue. You're not actually blocking in this case because you're telling dispatch_semaphore_wait to timeout immediately, which it's doing (returning non-zero, which evaluates in your if to true) - so you run through your while loop, where you drive the current run loop, and thus your enqueued block gets executed.

But my answer is broad because I'm not sure what part you're surprised by.

Wade Tregaskis
  • 1,947
  • 11
  • 12
  • "Because the default runloop on the main thread has the special behaviour that, when run, it also processes for the main dispatch queue." 1) Where could I know more about this "specific" behavior - could you describe it in details? 2) Is this behavior specific to only main queue/thread or to any serial queues/threads-other-than-main? 3) My second question: could you describe how it applied to the main queue, to any serial queue? I confirm that my surprise is expressed enough by the second question. – Stanislav Pankevich Nov 29 '12 at 07:32
  • 1
    It applies only to the main thread / dispatch queue. See the [docs](http://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW15). – Wade Tregaskis Nov 29 '12 at 16:31