GCD is the short form of Grand Central Dispatch. To understand GCD, there are several concepts needed to be known.

Task:

Task is a relatively abstract concept. It could be an operation, a function or a method. In most cases, we can consider a task to be a block(or closure in Swift).

QUEUE:

Queues are provided bt GCD to handle submitted tasks in FIFO order.

There are two kinds of queues:

  1. Serial Queue: execute tasks one at a time in the current thread, each task starting only after the preceding task has finished. This makes sure that no critical section happens.
  2. Concurrent Queue: execute tasks in multiple threads but still start in FIFO order. It is up tp GCD to determine whether one of the tasks should run on a different core.

How to create a queue:

1
2
3
4
5
6
// parameter 1: the name of the queue
// parameter 2:
// type of the queue:
// DISPATCH_QUEUE_SERIAL/NULL means serial queue,
// DISPATCH_QUEUE_CONCURRENT means concurrent queue
dispatch_queue_t serialQ = dispatch_queue_create("name", NULL);

The iOS system offers two kinds of queues: main queue and global queue.

The global queue is a concurrent queue. It has no name. We can get it by:

1
dispatch_queue_t Q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

The main queue is a serial queue. It is running on the main thread for UI updating. We can get it by:

1
dispatch_queue_t Q = dispatch_get_main_queue();

It is good to know that queue is like object which has reference counting. When a task is added to a queue, this queue will be retained, and the count++. The memory will be released when all the tasks in this queue are executed. It is important to create a queue with strong type.

SYNCHRONOUS VS. ASYNCHRONOUS

These terms describe when a function will return control to the caller, and how much work will have been done by that point.

A synchronous function returns only after the completion of a task that it orders. No new thread and it will block current thread.

An asynchronous function, on the other hand, returns immediately, ordering the task to be done but not waiting for it. Thus, an asynchronous function does not block the current thread of execution from proceeding on to the next function. GCD will open a new thread if there are available threads. It will now block current thread. (Part from raywenderlich.com)

The functions to achieve Synchronous and Asynchronous execution:

1
2
3
4
5
6
7
/* synchronous
perameter 1:the queue need to be executed
perameter 2:the block
*/
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
// asynchronous
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

FOUR CASES

There are two kinds of queues: serial queue and concurrent queue. And there are two kinds of execution. So 2 by 2, there are four cases. What is happening for each of them?

  1. Synchronously execute a serial queue: Synchronous means no new thread. So, it will execute the tasks one after preceding one in the current thread.
  2. Asynchronously execute a serial queue: Asynchronous means new threads might be opened. But if GCD opened multiple threads, it can not guaranty that the tasks in the serial queue will be executed in FIFO order. So, only one thread will be opened.
  3. Synchronously execute a concurrent queue: Synchronous means no new thread. So, just execute in order.
  4. Asynchronously execute a concurrent queue: GCD will open multiple threads based on current condition, and take tasks out of the queue in order, but execute them in disorder.

DEADLOCK

Threads are said to be deadlocked if they all get stuck waiting for each other to complete or perform another action. The first can’t finish because it’s waiting for the second to finish. But the second can’t finish because it’s waiting for the first to finish. (From raywenderlich.com)

Remember! On a serial queue, never call dispatch_sync targeting the same queue!

For example, deadlock the main thread:

1
2
3
4
5
6
7
8
9
10
- (void)mainThreadDeadLockTest {
NSLog(@"begin");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"middle");
});
NSLog(@"end");
}

// nslog print out:
// begin

The main queue is a serial queue. The dispatch_sync will block current queue which is the main queue to run the code in the dispatch block. But here, in the dispatch_sync, we added a task to the main queue to execute. However, the main queue is already blocked. It can not execute the block.

Deadlock anther custom serial thread:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)deadLockTest {
dispatch_queue_t serialQueue = dispatch_queue_create("serial_queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
NSLog(@"begin");
dispatch_sync(serialQueue, ^{
NSLog(@"middle");
});
NSLog(@"end");
});
NSLog(@"return");
}

// nslog print out
return
begin

The new serial queue is a deadlock, but it will not affect the main thread.