1
votes

I am reading a iOS book which says that "dispatch_sync function blocks the concurrent queue to which the block is submitted i.e it makes the queue wait". Based on that concept I created my own example which is as follows.The following snippet is written in the "viewDidLoad" method

dispatch_queue_t concQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

void (^secondBlock)(void) =^( void)
{

    //Second Block
    for (int count=0; count<1000; count++)
    {

        if( [NSThread currentThread] == [NSThread mainThread ] )
        {
            NSLog(@"2 block main Thread") ;
        }
        else
        {

            NSLog(@"2  block other THREAD") ;
        }
    }

};



void (^firstBlock)(void) =^( void)
{
    //First Block
    for (int count=0; count<100; count++)
    {

        if( [NSThread currentThread] == [NSThread mainThread ] )
        {
            NSLog(@"1 block  main Thread") ;
        }
        else
        {

            NSLog(@"1 block other THREAD") ;
        }
    }


    dispatch_sync(concQueue1, secondBlock) ;

};



dispatch_async(concQueue1,firstBlock);

//Making the main thread sleep for some time
[NSThread sleepForTimeInterval:0.1] ;

dispatch_async( concQueue1, ^(void) {

    //Third Block
    for (int count=0; count<1000; count++)
    {

        if( [NSThread currentThread] == [NSThread mainThread ] )
        {
            NSLog(@"3 block main Thread") ;
        }
        else
        {

            NSLog(@"3 block other THREAD") ;
        }
    }

});

I am making the main thread sleep for some time so that dispatch_sync function in the "first block " gets executed. The output i am getting is this. I am showing the part of the output.

GCDExamples[2459:554259] 2 block other THREAD

.

.

.

GCDExamples[2459:554259] 2 block other THREAD

GCDExamples[2459:554256] 3 block other THREAD

GCDExamples[2459:554256] 3 block other THREAD

GCDExamples[2459:554259] 2 block other THREAD //Point first

GCDExamples[2459:554256] 3 block other THREAD

Some points about the output : The output shown in "3 block other THREAD" and "2 block other THREAD" are the first occurences of that output lines

MY QUESTION: According to the concept because of dispatch_sync function once the second block starts it should make the queue wait rather than allowing "Third block" to start. But as shown in the earlier output "2 block other THREAD" follows "3 block other THREAD" statement at "//Point first" .This shows that the dispatch_sync function did'nt make the queue wait. How is that possible?? .Please ask me any another other infomration if needed.

EDIT 1 : I am putting the text of the well known book here to explain my point . The book is "iOS 7 Programming cookbook". Text follows:- "For any task that doesn’t involve the UI, you can use global concurrent queues in GCD. These allow either synchronous or asynchronous execution. But synchronous execution does not mean your program waits for the code to finish before continuing. It simply means that the concurrent queue will wait until your task has finished before it continues to the next block of code on the queue. When you put a block object on a concurrent queue, your own program always continues right away without waiting for the queue to execute the code. This is because concurrent queues, as their name implies, run their code on threads other than the main thread."

As the bold text says that the concurrent queue would wait UNTIL my task is finished before continuing with the next block. My block printing "2 block other THREAD" should be allowed to finish before "3 block other THREAD" starts, but that is not the case my " 2 block other THREAD" is printed again intermingling with "3 block other THREAD" statement when in fact my all "2 block other THREAD" should be allowed to get completed and then "3 block other THREAD" should follow. Comment if more info is required.

2
I think you mix up sync/async with concurrent/serial. Sync waits the block to finish. Async add the block to the queue and continue the execution. Concurrent runs multiple blocks concurrently and serial run them one by one in order they have been added. dispatch_get_global_queue returns a well-known global concurrent queue. Which runs multiple blocksryancrunchi
Kindly read the "Edit 1 " of my questionLearneriOS
As your queue is concurrent and you run block1 and block3 async, they will run concurrently (block3 delayed by 0.1 second). The block2 will make the queue to wait until block2 has finished but in the block1, which is async.ryancrunchi
I am sorry, I could not understand the last line of your comment . Can you elaborate on that please. I am sure that even if the block 2 is in the block1 at the end of the day it would be added to the queue itself.LearneriOS
Your block2 is called in block1. So it runs block2 in block1 and the execution of block1 waits at this line dispatch_sync(concQueue1, secondBlock) ; until block2 finished. As block1 is async, it waits async. And your block3 runs async too.ryancrunchi

2 Answers

3
votes

"dispatch_sync function blocks the concurrent queue to which the block is submitted i.e it makes the queue wait"

If that's what the book says, throw it away. That's just wrong.

Synchronous vs. asynchronous is about the caller. When some code calls dispatch_sync(), that code can not proceed until the task being dispatched has completed. The queue is not blocked or forced to wait or anything like that.

By contrast, when code calls dispatch_async(), the task is put on the queue and the caller proceeds to its next step. It does not wait for the task that was dispatched to start, let alone finish.

That's a completely separate issue from whether a queue is concurrent or serial. That distinction belongs to the queues and the tasks they run, but doesn't directly affect the caller. A serial queue will only run one task at a time. If other tasks have been queued, they wait and run in strict sequence.

A concurrent queue can allow multiple tasks to run at the same time, depending on available system resources.


Update in response to edited question with new quote from the book:

For any task that doesn’t involve the UI, you can use global concurrent queues in GCD. These allow either synchronous or asynchronous execution. But synchronous execution does not mean your program waits for the code to finish before continuing. It simply means that the concurrent queue will wait until your task has finished before it continues to the next block of code on the queue. When you put a block object on a concurrent queue, your own program always continues right away without waiting for the queue to execute the code. This is because concurrent queues, as their name implies, run their code on threads other than the main thread.

This continues to be completely wrong. To take it part by part:

But synchronous execution does not mean your program waits for the code to finish before continuing.

That's exactly what "synchronous execution" does mean. When you submit a task synchronously, the submitting thread waits for the code to finish before continuing.

It simply means that the concurrent queue will wait until your task has finished before it continues to the next block of code on the queue.

No. The whole point of concurrent queues is that they don't wait for one task that is running before starting subsequent tasks. That's what "concurrent" means. A concurrent queue can run multiple tasks concurrently, at the same time, simultaneously.

When you put a block object on a concurrent queue, your own program always continues right away without waiting for the queue to execute the code.

No, this is wrong. It completely depends on what function you use to put that block on the queue. If it uses dispatch_sync(), it waits for the queue to execute the block. If it uses dispatch_async(), it does not wait; it continues right away. This is true whether the queue is serial or concurrent.

This is because concurrent queues, as their name implies, run their code on threads other than the main thread.

Any queue, serial or concurrent, other than the main queue, may run the blocks submitted to it on a background thread. And, if you use dispatch_sync() to submit a block to a concurrent queue from the main thread, it's very possible that the block will execute on the main thread. That's because GCD knows that the main thread isn't doing anything else, because it's blocked inside of the dispatch_sync() call, so it might as well run the block there.

In other words, the type of queue does not dictate which thread the block runs on.

The author of this book simply doesn't know what s/he is talking about.

0
votes

First to understand, GCD you have to understand the difference between synchronous and asynchronous execution.

Synchronous = Executes as they are submitted and blocks the thread/queue they are submitted on.This means that:

  1. The block (of code) only executes when it is it's turn in the queue.
  2. The block (of code) will block the queue for executing and other blocks(of code & synchronous) will wait.

Basically the blocks will execute in a FIFO format.

Asynchronous = Starts executing immediately regardless of the queue/thread and does not block queue/thread.Executes even if something is executing on the queue(both synchronous and asynchronous).

To understand what when wrong, we will work through the code.

  1. Lines 1-19 - Defined secondBlock
  2. Lines 23-43 - Defined firstBlock
  3. Line 47 - dispatch_async() firstBlock (Remember:Asynchronous execution)
  4. Line 41[firstBlock] dispatch_sync() secondBlock (Remember: Synchronous execution)
  5. Line 43[firstBlock] - firstBlock exits
  6. Line 50 - Thread sleeps for 0.1 seconds
  7. Line 52 - Define and Execute thirdBlock (Remember: Asynchronous execution).

The thirdBlock was executing asynchronously and started executing even if there is secondBlock executing on the queue.To achieve queuing of blocks(of code), us dispatch_sync().

Note

This functions operate relative to the concurrent queue.This means that dispatch_sync() will only be synchronous to the current queue. On other threads (such as the main thread) it appears to be asynchronous.