10
votes

I am executing a block using dispatch_sync and the block is executed correctly. But this block is executed on the main thread. As per the Apple Doc:

Serial queues (also known as private dispatch queues) execute one task at a time in the order in which they are added to the queue. The currently executing task runs on a distinct thread (which can vary from task to task) that is managed by the dispatch queue.

which means (or what I understood) that current process that is being executed will run on a separate thread.

Below is the code that I am using to judge what's going on. It is being called inside NSURLConnection's didReceiveData: delegate method (I know I should not do that inside the didReceiveData: delegate method - but this is just a sample to focus on dispatch_sync). Following are the different ways that I can assume as a proof of my conclusion:

  1. Using dispatch_sync on a Global Concurrent Queue

       dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
            if ([NSThread isMainThread]) {
                NSLog(@"Main Thread");
            }
            else
                NSLog(@"Not on Main Thread");
    
            //Some Process
        });
    

Output -

         Main Thread
         Main Thread 
         Main Thread
         // Main Thread printed till didReceiveData: gets called

  1. Using dispatch_sync on a self created queue using dispatch_queue_create

    // Create queue somewhere else like this
    dispatch_queue_t newQueue = dispatch_queue_create("WriteQueue", DISPATCH_QUEUE_SERIAL);
    
    
       dispatch_sync(newQueue, ^{
    
            if ([NSThread isMainThread]) {
                NSLog(@"Main Thread");
            }
            else
                NSLog(@"Not on Main Thread");
    
            //Some Process
        });
    

Output -

         Main Thread
         Main Thread 
         Main Thread
         // Main Thread printed till didReceiveData: gets called

I am a bit surprised here, block is executed always on the main thread or am I missing something. Because it seems to be going against the Apple Doc I think so. Does anyone know what this is all about?

Update: As per other discussions I understand that dispatch_sync executes a block on the same thread (most of the times), then why apple docs' statements are contradicting in some ways. Why apple says "The currently executing task runs on a distinct thread (which can vary from task to task) that is managed by the dispatch queue." Or am I still missing something?

4
maybe NSThread is not aware of queues…vikingosegundo
@vikingosegundo what do you mean by "not aware"?Evol Gate
NSThread is a old piece of software, while dispatch_queues are new. maybe NSThreads are just not aware of queuesvikingosegundo
or at least not fully — I dont know, just an idea.vikingosegundo
or your sample just does not work as you expect, as Ramy points out in his edit.vikingosegundo

4 Answers

15
votes

dispatch_sync() dispatches the block on the same thread, that's normal.

EDIT

Apple's Documentation does not only says this, also says this:

As an optimization, this function invokes the block on the current thread when possible.

As a side note (I know you're talking about the synchronous version, but let's precisate this) I would say that also dispatch_async() may cause multiple blocks to be executed in the same thread.

5
votes

For a background block, use

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // background code
});

Note it's _async and not _sync

EDIT: Likewise, to execute something on main thread, use

dispatch_async(dispatch_get_main_queue(), ^{
    // main thread code
});
4
votes

It is important to realize that Grand Central Dispatch can guarantee that a block submitted to the main queue will run on the main thread, but a block submitted to any other queue has no guarantees about what thread a block will execute on.

No guarantee is made regarding which thread a block will be invoked on; however, it is guaranteed that only one block submitted to the FIFO dispatch queue will be invoked at a time.

Grand Central Dispatch manages a pool of threads and reuses existing threads as much as possible. If the main thread is available for work (i.e. idle) a block can be executed on that thread.

0
votes

Here is how you can do this in Swift:

runThisInMainThread { () -> Void in
    // Runs in the main thread
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

Its included as a standard function in my repo, check it out: https://github.com/goktugyil/EZSwiftExtensions