preface

In the last article, we explored several forms of multithreading and also mentioned the use of GCD, so this article will focus on the exploration of GCD.

Resources to prepare

  • Libdispatch source

The summary of the GCD

  • GCD — Grand Central Dispatch;

  • Pure C, for example, provides very powerful functions;

  • GCD adds a task to a queue and specifies the function that the task executes.

GCDThe advantage of

  • GCD is apple’s solution for multi-core parallel computing.

  • GCDS automatically utilize more CPU cores (e.g., dual-core, quad-core);

  • GCD automatically manages the thread lifecycle (thread creation, task scheduling, thread destruction);

  • The programmer only needs to tell the COMMUNIST party what task it wants to perform, without writing any thread management code.

GCDOn the basis of

The basic usage code is as follows:

dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
    NSLog(@"%@",[NSThread currentThread]);
});
Copy the code

Back to the basics, which can be broken down into tasks, queues, and functions:

  • Create tasks using dispatch_block_t:

    • Tasks are encapsulated with blocks.

    • The block of the task takes no arguments and returns no values;

  • Create a queue using dispatch_queue_t;

  • Adds the task to the queue and specifies the function dispatch_async that performs the task.

Here is a code demonstration:

- (void)syncTest{// Dispatch_block_t block = ^{NSLog(@"hello GCD"); }; // dispatch_queue_t queue = dispatch_queue_create("com.lg.cn", NULL); // dispatch_async(queue, block); }Copy the code

function

There are two ways to execute tasks in the GCD, synchronous and asynchronous:

  • Dispatch_sync: synchronization function

  • Dispatch_async: asynchronous function

dispatch_sync

The dispatch_sync function has the following features:

  • You must wait for the current statement to complete before executing the next statement.

  • Does not open the thread, that is, does not have the ability to open a new thread;

  • Execute a block task in the current thread.

dispatch_async

The asynchronous function dispatch_async has the following features:

  • The next statement can be executed without waiting for the current statement to complete.

  • The ability to start new threads (but not necessarily new threads, depending on the queue type specified by the task);

  • Asynchrony is a synonym for multithreading;

The difference between the two

  • Whether the tasks in the waiting queue are completed.

  • Whether you have the ability to start new threads.

The queue

Queues are divided into serial queues and concurrent queues for storing tasks. A queue is a data structure that belongs to a special linear table and follows the first-in, first-out (FIFC) principle. New tasks are inserted at the end of the queue, and tasks are read from the head of the queue. For each task read, a task is released from the queue.

In GCD, two special queues are also provided, namely the primary queue and the global concurrent queue. The main queue belongs to the serial queue, while the global concurrent queue belongs to the concurrent queue.

Queue and thread have no relationship, queue is responsible for task scheduling, task execution depends on thread, priority scheduling task may not be priority execution;

Serial queues

Serial Dispatch Queue:

  • Only one task is executed at a time. The next task is executed after the previous task is completed.

  • Only one thread is started and only one task is scheduled at a time.

  • Create serial queues with DISPATCH_QUEUE_SERIAL;

  • DISPATCH_QUEUE_SERIAL can also be passed NULL and is created as a serial queue by default.

dispatch_queue_t serialQueue1 = dispatch_queue_create("com.lg.serial", NULL);
dispatch_queue_t serialQueue2 = dispatch_queue_create("com.lg.serial", DISPATCH_QUEUE_SERIAL);
Copy the code

Concurrent queue

Concurrent Dispatch Queue:

  • Multiple tasks can be executed concurrently at a time.

  • Open multiple threads, at the same time can schedule multiple tasks to execute;

  • Create a concurrent queue using DISPATCH_QUEUE_CONCURRENT;

  • The concurrency capabilities of concurrent queues are only available for asynchronous functions.

dispatch_queue_t concurrentQueue = dispatch_queue_create("com.lg.concurrent", DISPATCH_QUEUE_CONCURRENT);
Copy the code

The home side column

Main Dispatch Queue:

  • Main queue: a special serial queue provided by the GCD;

  • A serial queue that is used to schedule tasks on the main thread, depending on the main thread, the main Runloop, and is created automatically before the main function is called;

  • Threads will not be opened;

  • If a task is currently running on the main thread, whatever task is currently added to the main queue will not be scheduled.

  • Use dispatch_get_main_queue to obtain the primary queue.

  • Usually used when returning to the main thread to update the UI.

dispatch_queue_t mainQueue = dispatch_get_main_queue();
Copy the code

Global concurrent queue

Global Dispatch Queue:

dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
Copy the code
  • The default concurrency queue provided by GCD;

  • For developers’ convenience, Apple provides global queues;

  • When using multi-threaded development, if there is no special need for queues, when performing asynchronous tasks, you can directly use global queues;

  • Dispatch_get_global_queue (0, 0) :

    • Parameter 1 indicates the queue priority. The default priority is DISPATCH_QUEUE_PRIORITY_DEFAULT = 0, which is replaced by quality of service.

    • Parameter 2 is a marker reserved for future use. So this argument should always be 0;

Priority from high to low, corresponding to service quality:

  • DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED

  • DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT

  • DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY

  • DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND

In daily development, use of main queue + global concurrent queue:

Dispatch_async (dispatch_get_global_queue(0, 0), ^{dispatch_async(dispatch_get_main_queue()), ^{// return to main thread for UI}); });Copy the code

The use of queues and functions

Serial queue and function collocation

Synchronization function

  • Does not start the thread and executes in the current thread.
  • Tasks are executed sequentially, one after the other.

Code verification:

/** Serial sync queue: FIFO: */ - (void)serialSyncTest{//1: dispatch_queue_t queue = dispatch_queue_create("Cooci", DISPATCH_QUEUE_SERIAL); for (int i = 0; i<5; i++) { dispatch_sync(queue, ^{ NSLog(@"%d-%@",i,[NSThread currentThread]); }); } NSLog(@"hello queue"); }Copy the code

Print result:

An asynchronous function

  • Start a new thread.
  • Tasks are executed sequentially, one after the other;

Code verification:

Dispatch_queue_t queue = dispatch_queue_create("Cooci", DISPATCH_QUEUE_SERIAL); for (int i = 0; i < 5; i++) { dispatch_async(queue, ^{ NSLog(@"%d-%@",i,[NSThread currentThread]); }); } NSLog(@"hello queue"); }Copy the code

Print result:

Concurrency queue and function collocation

Synchronization function

  • Does not start the thread and executes in the current thread.
  • Tasks are executed sequentially, one after the other.

Code verification:

/** Block the lock queue: Resume supend thread operation, */ - (void)concurrentSyncTest{//1: create a concurrent queue dispatch_queue_t queue = dispatch_queue_create("Cooci", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 5; i++) { dispatch_sync(queue, ^{ NSLog(@"%d-%@",i,[NSThread currentThread]); }); } NSLog(@"hello queue"); }Copy the code

Print result:

An asynchronous function

  • Start a new thread.
  • Tasks are executed asynchronously, in no order, andCPUScheduling concerns.

Code verification:

/** Async concurrency: */ - (void)concurrentAsyncTest{//1: dispatch_queue_t queue = dispatch_queue_create("Cooci", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i<100; i++) { dispatch_async(queue, ^{ NSLog(@"%d-%@",i,[NSThread currentThread]); }); } NSLog(@"hello queue"); }Copy the code

Print result:

Main queue and function collocation

Synchronization function

  • A serial queue used to schedule tasks on the main thread.

  • Adding a synchronization function to the main queue causes the main thread to wait for the synchronization function to complete.

  • Because the main queue is a special serial queue, the synchronization function needs to wait for the main queue to complete before execution.

  • So, two tasks wait for each other, creating a deadlock.

Code validation: crashes directly:

An asynchronous function

  • Does not start the thread and executes in the current thread.
  • Tasks are executed sequentially, one after the other.

Code verification:

/** mainAsyncTest{dispatch_queue_t queue = dispatch_get_main_queue(); /** mainAsyncTest{dispatch_get_main_queue(); for (int i = 0; i<5; I ++) {dispatch_async(queue, ^{NSLog(@"%d: %@", I,[NSThread currentThread]); }); } NSLog(@"hello queue"); }Copy the code

Print result:

Collocation of global queues and functions

Synchronization function

  • Does not start the thread and executes in the current thread.
  • Tasks are executed sequentially, one after the other.

Code verification:

*/ - (void)globalSyncTest{for (int I = 0; i<5; i++) { dispatch_sync(dispatch_get_global_queue(0, 0), ^{ NSLog(@"%d-%@",i,[NSThread currentThread]); }); } NSLog(@"hello queue"); }Copy the code

Print result:

An asynchronous function

  • Start a new thread.
  • Tasks are executed asynchronously, in no order, andCPUScheduling concerns.

Code verification:

*/ - (void)globalAsyncTest{for (int I = 0; i<20; i++) { dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"%d-%@",i,[NSThread currentThread]); }); } NSLog(@"hello queue"); }Copy the code

Print result:

The thread deadlock

The so-called thread deadlock refers to the fact that two or more threads hold resources needed by each other, so that these threads are in a waiting state and cannot execute

Deadlocks cause crashes:

If you look at the stack, you’ll see a call to _dispatch_SYNC_F_SLOW, which is a deadlock exception

Analysis of interview questions

The interview questions 1

- (void)wbinterDemo { dispatch_queue_t queue = dispatch_queue_create("com.lg.cn", DISPATCH_QUEUE_CONCURRENT); NSLog(@" order 1: %@",[NSThread currentThread]); Dispatch_async (queue, ^{NSLog(@" order 2: %@",[NSThread currentThread]); Dispatch_async (queue, ^{NSLog(@" order 3: %@",[NSThread currentThread]); }); NSLog(@" order 4: %@,[NSThread currentThread]); }); NSLog(@" order 5: %@",[NSThread currentThread]); }Copy the code

Analysis: (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) All that is left is the contents of the asynchronous thread. In the asynchronous thread, there is no sorting operation, so we print order 2, order 4, and there is an asynchronous thread, so we print order 3.

View the print result:

The interview questions 2

- (void)wbinterDemo1{ dispatch_queue_t queue = dispatch_queue_create("com.lg.cn", DISPATCH_QUEUE_CONCURRENT); NSLog(@" order 1: %@",[NSThread currentThread]); Dispatch_async (queue, ^{NSLog(@" order 2: %@",[NSThread currentThread]); Dispatch_sync (queue, ^{NSLog(@" order 3: %@",[NSThread currentThread]); }); NSLog(@" order 4: %@,[NSThread currentThread]); }); NSLog(@" order 5: %@",[NSThread currentThread]); }Copy the code

Analysis: (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) (DISPATCH_QUEUE_CONCURRENT) The rest is the contents of the asynchronous thread, in the asynchronous thread there is no sorting operation, but there is also a synchronous thread, serial execution, so directly print order 2, order 3, order 4.

Print result:

The interview question 3

- (void)wbinterDemo4 { dispatch_queue_t queue = dispatch_queue_create("com.lg.cn", NULL); NSLog(@" order 1: %@",[NSThread currentThread]); Dispatch_async (queue, ^{NSLog(@" order 2: %@",[NSThread currentThread]); Dispatch_sync (queue, ^{NSLog(@" order 3: %@",[NSThread currentThread]); }); NSLog(@" order 4: %@,[NSThread currentThread]); }); NSLog(@" order 5: %@",[NSThread currentThread]); }Copy the code

Analysis: Firstly, serial queue is determined. Sequence 1 and 5 are in the main queue and are not affected. Asynchronous function executes sequence 2 first, but sequence 4 waits for synchronous function to execute first. Because of the use of serial queues, synchronous functions need to be executed after the completion of asynchronous functions, so the two functions wait for each other, resulting in a deadlock.

Print result:

The interview question 4

- (void)wbinterDemo{ dispatch_queue_t queue = dispatch_queue_create("com.lg.cooci.cn", DISPATCH_QUEUE_SERIAL); Dispatch_async (queue, ^{NSLog(@" order 1"); }); Dispatch_async (queue, ^{NSLog(@" order 2"); }); Dispatch_sync (queue, ^{NSLog(@" order 3"); }); NSLog (@ order "0"); Dispatch_async (queue, ^{NSLog(@" order 7"); }); Dispatch_async (queue, ^{NSLog(@" order 8"); }); Dispatch_async (queue, ^{NSLog(@" order 9"); }); }Copy the code

There are 4 options:

  • A: 1230789
  • B: 1237890
  • C: 3120798
  • D: 2137890

C

First, determine the serial queue, execute sequence 1 and sequence 2 in the asynchronous function, so the order is uncertain; In a synchronization function, order 0 is in the main thread, so order 3 must precede order 0; The orders 7, 8, and 9 must be executed after 3 and 0, but they are in asynchronous functions, so the order is also uncertain.

Topic 5

How many types of queues are there?

Correct answer: two

  • Serial queues: serialQueue and mainQueue

  • Concurrent queues: concurrentQueue, globalQueue

- Serial Dispatch Queue dispatch_queue_t serialQueue = dispatch_queue_create("com.lg.cn", NULL); -concurrent Dispatch Queue dispatch_queue_t concurrentQueue = dispatch_queue_create("com.lg.cn", DISPATCH_QUEUE_CONCURRENT); -dispatch Queue dispatch_queue_t mainQueue = dispatch_get_main_queue(); -global Dispatch Queue dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);Copy the code

Topic 6

@property (atomic, assign) int num; 

- (void)MTDemo {
    while (self.num < 5) { 
        dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
            self.num++;
        }); 
    } 
    NSLog(@"end : %d",self.num); 
}
Copy the code
  • Correct answer:> = 5.
  • First of all a bitnumThe value of cannot be less than5, because less than5When, is unable to get outwhileThe loop.
  • All the above are asynchronous functions, which leads tonumA value of5There could be a mission going onself.num++Operation, sonumThe value of may be greater than5.

The interview question 7

for (int i= 0; i<10000; i++) {

        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.num++;
        });
    }

    NSLog(@"end : %d",self.num);
}
Copy the code
  • This interview question is different from the one above, where the conditional judgment and increment are not using the same variable, the code will loop10000Keep addingself.num++Mission, which leads us to execute++When operating, it is possiblenumThe value of theta has gotten bigger, but we’re still adding the smaller value, so it’s going to end up< = 10000.