dispatch_sync always scheduling a block on Main Thread

10,908

Solution 1

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.

Solution 2

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
});

Solution 3

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.

Share:
10,908
Evol Gate
Author by

Evol Gate

Updated on June 14, 2022

Comments

  • Evol Gate
    Evol Gate almost 2 years

    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
    Evol Gate over 11 years
    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
    Evol Gate over 11 years
    Yeah I already know that, but it contradicts with the apple doc
  • Joshua Nozzi
    Joshua Nozzi over 11 years
    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.
  • Evol Gate
    Evol Gate over 11 years
    @JoshuaNozzi I think you're correct. I need to file a bug and ask for clarification
  • Evol Gate
    Evol Gate over 11 years
    @RamyAlZuhouri The point that you quoted above - Is it also written in docs for iOS, because I only saw it in Mac development docs.
  • Ramy Al Zuhouri
    Ramy Al Zuhouri over 11 years
    @Evol Gate it's written in both documentations: iOS and OS X.
  • Victor Engel
    Victor Engel almost 11 years
    @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.
  • Ismael
    Ismael almost 11 years
    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
  • Nisar Ahmad
    Nisar Ahmad about 6 years
    @quelish your answer make sense . . . would you like to share the reference of your comments I mean any Apple Doc link ? Thanks
  • quellish
    quellish about 6 years
    @NisarAhmad, it is in the headers: opensource.apple.com/source/libdispatch/libdispatch-913.30.4‌​/… as well as man dispatch_queue_create
  • XLE_22
    XLE_22 about 6 years
    @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)