Search code examples
objective-cgrand-central-dispatch

How to ensure two gcd queues run on separate threads?


I'm in a situation where I want to ensure two queues end up executing on different threads. Ideally, I'd like to ensure they're serial queues. In particular, in the example below, if both queues run on the same thread, doStuff will be busy-waiting indefinitely. Am I going to have to move to explicit threading or can I salvage use of GCD here?

- (void)foo {
    self.responseQueue = dispatch_queue_create("com.blah.response", DISPATCH_QUEUE_SERIAL);

    self.requestQueue = dispatch_queue_create("com.blah.request", DISPATCH_QUEUE_SERIAL);

    dispatch_async(self.requestQueue, ^{
        [self doStuff];
    });
}

- (BOOL)doStuff {
    BOOL __block waiting = YES;

    self.responseBlock = ^{
        waiting = NO;
    };

    [self performRequest];

     while (waiting) {
         // realize could use dispatch_semaphore (busy waiting just to illustrate point).    
         sleep(1);
     }

     [self doStuffRequiringResponseCompletion];

     // I realize it would be sensible to 
     // 1) Not block in the above while loop.
     // 2) Call |doStuffRequiringResponseCompletion| after |receivedResponse|.
     // I don't want to do this.
}

// method called on arbitrary thread
- (void)receivedResponse {
    // stuff

    dispatch_async(self.responseQueue, self.responseBlock);
}

See also: Is there any reason to not use sleep in a Grand Central Dispatch queue??


Solution

  • I don't recommend using this solution because dispatch queues should not be abused for synchronization purposes but something like this is what I was after (however this is not guaranteed to not deadlock - deadlock could occur if the dispatch_sync block ran on a different thread than the one spun up by performSelectorInBackground):

    - (void)foo {
        self.responseQueue = dispatch_queue_create("com.blah.response", DISPATCH_QUEUE_SERIAL);
    
        self.requestQueue = dispatch_queue_create("com.blah.request", DISPATCH_QUEUE_SERIAL);
    
        [self performSelectorInBackground:@selector(dispatchRequest) withObject:nil]
    }
    
    - (void)dispatchRequest {
        dispatch_sync(self.requestQueue, ^{
            [self doStuff];
        });
    }