10

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?

Evol Gate
  • 2,247
  • 3
  • 19
  • 37
  • maybe NSThread is not aware of queues… – vikingosegundo Dec 20 '12 at 12:30
  • @vikingosegundo what do you mean by "not aware"? – Evol Gate Dec 20 '12 at 12:33
  • NSThread is a old piece of software, while dispatch_queues are new. maybe NSThreads are just not aware of queues – vikingosegundo Dec 20 '12 at 12:34
  • or at least not fully — I dont know, just an idea. – vikingosegundo Dec 20 '12 at 12:36
  • or your sample just does not work as you expect, as Ramy points out in his edit. – vikingosegundo Dec 20 '12 at 12:38
  • Definitely see this answer: http://stackoverflow.com/a/14716650/8047 – Dan Rosenstark Feb 05 '13 at 21:23
  • @vikingosegundo you're actually right. I didn't know this before. – Dan Rosenstark Feb 05 '13 at 21:24
  • @Yar I looked at the above link you provided. I know everyone say that block on dispatch_sync is executed on the same thread, even the apple docs say that but it also says a contradictory point that I mentioned above. Trust me Yar, I am still confused by the statements from Apple Doc. Can you anyhow tell me why apple says " The currently executing task runs on a distinct thread ......." – Evol Gate Feb 06 '13 at 03:37
  • Not much use calling `dispatch_sync()` from the main thread since it waits until the block completes before it returns. Might as well just run the block directly. Consider using `dispatch_async()` which add the block to the queue and returns immediately. – Marcus Adams Aug 05 '14 at 12:57
  • @EvolGate . I have the same question in my mind but not get any satisfaction from the answers/Comments etc. Have you got any information .? – Nisar Ahmad Feb 07 '18 at 03:39

4 Answers4

15

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.

Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187
  • 1
    Yeah I already know that, but it contradicts with the apple doc – Evol Gate Dec 20 '12 at 12:23
  • I don't see it as a contradiction but more an affirmation (your bolded part) that it's not up to you to choose the target thread for the used queue nor is it guaranteed to be consistent. Still, file a bug against the docs and ask for clarification on this point. – Joshua Nozzi Dec 20 '12 at 13:24
  • @JoshuaNozzi I think you're correct. I need to file a bug and ask for clarification – Evol Gate Dec 20 '12 at 14:59
  • @RamyAlZuhouri The point that you quoted above - Is it also written in docs for iOS, because I only saw it in Mac development docs. – Evol Gate Dec 20 '12 at 15:00
  • @Evol Gate it's written in both documentations: iOS and OS X. – Ramy Al Zuhouri Dec 20 '12 at 18:07
5

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
});
Ismael
  • 3,927
  • 3
  • 15
  • 23
  • I already mentioned it is just to focus on dispatch_sync. I know i can do it using dispatch_async(dispatch_get_main_queue() – Evol Gate Dec 20 '12 at 12:23
  • @Ismael, what if dispatch_async(dispatch_get_main_queue(), ...) is called from the main queue. According to the doc, if I'm reading it right, that would cause a deadlock. – Victor Engel Jun 28 '13 at 03:03
  • No, it will not cause a deadlock. Most likely it will be added to the main thread queue and be processed after the thread is freed – Ismael Jul 03 '13 at 19:34
4

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.

quellish
  • 21,123
  • 4
  • 76
  • 83
  • @quelish your answer make sense . . . would you like to share the reference of your comments I mean any Apple Doc link ? Thanks – Nisar Ahmad Feb 14 '18 at 03:03
  • 2
    @NisarAhmad, it is in the headers: https://opensource.apple.com/source/libdispatch/libdispatch-913.30.4/dispatch/queue.h.auto.html as well as `man dispatch_queue_create` – quellish Feb 21 '18 at 20:28
  • @quelish : if the MainThread may be used in another queue than the MainQueue, does it mean that the associated current loop at that time is the MainRunLoop ? (I understood a loop is associated with a thread) – XLE_22 Mar 21 '18 at 09:36
0

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

Esqarrouth
  • 38,543
  • 21
  • 161
  • 168