You just need to know how to open threads and look at relevant third-party frameworks.

Introduction to the

Two core concepts

Task: What operation is performed queue: Used to store tasks

Queue type:

  • Concurrent queue(Concurrent Dispatch Queue)

Multiple tasks can be executed concurrently (automatically enabling multiple threads to execute tasks at the same time) with asynchronous dispatch_async

  • Serial queues(Serial Dispatch Queue)

Let tasks be executed one after another (after one task is executed, the next) in FIFO order.

Assignment:

  • synchronous

Block the current thread until the added time-consuming task Block is complete before the function can return and subsequent code can continue.

  • asynchronous

After a task is added to a queue, the function returns immediately and the following code executes immediately without waiting for the added task to complete. Asynchronous commit cannot determine the task execution order.

GCD multithreading often uses the synchronous function dispatch_sync and asynchronous function dispatch_async to add tasks to a specified queue.

To distinguish between

The execution effect of various queues

Main queue (a serial queue)

Any task placed in the main queue must be executed in the main thread.

1. Asynchronous function + main queue

In serial execution, all tasks are executed in the main thread without opening the thread

2. Synchronization function + main queue ———— will deadlock! Not usually.

Characteristics of the main queue: If the main queue finds a task running on the main thread, it suspends the task in the queue until the main thread is idle.

GCD implements communication between threads

Description: Returned to the main thread when updating the UI (by creating a new synchronous/asynchronous function with queue parameters as the main queue)

  • Open child threads to do asynchronous tasks
dispatch_async(dispatch_get_global_queue(0, 0), ^{ //... Dispatch_sync (dispatch_get_main_queue(), ^{// back to main thread, update UI}); });Copy the code

For example, start a child thread to download an image

Dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); __weak typeof(self) weakSelf = self; //2. Add the task to the queue and execute dispatch_async(queue, ^{NSURL *url = [NSURL URLWithString:_imgString]; NSData *imageData = [NSData dataWithContentsOfURL:url]; UIImage * bgImage = [UIImage imageWithData:imageData]; bgImage = [bgImage applyLightEffectAtFrame:CGRectMake(0, 0, bgImage.size.width, bgImage.size.height)]; / / 3. Return to the main thread dispatch_async (dispatch_get_main_queue (), ^ {weakSelf. BackImageView. Image = bgImage; }); });Copy the code

GCD common functions

  • Delay the
Int64_t delayInSeconds = 10.0; // Delay time dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // do something ... . }); Or dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), dispatch_get_main_queue(), ^ {/ /... });Copy the code
  • One-time code

This application is executed once and never again

    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        //...
    });
Copy the code

Cannot be applied to lazy loading. Apply to the singleton pattern.

  • Barrier function

It is used to control the execution sequence of asynchronous functions. Only after the fence function is executed, can the queue tasks be executed. When used, you must create your own queue and cannot use global concurrent queues.

There is no need to use fence function for synchronization function.

  • Fast iteration (traversal)

Internally, child threads and the main thread are opened to complete the traversal task, and the task is executed asynchronously

  • Main thread asynchronous task
    dispatch_async(dispatch_get_main_queue(), ^{
    
    });
Copy the code
  • Barrier function

Used to control the order in which asynchronous functions are executed. Data competition can be avoided. When used, you must create your own queue and cannot use global concurrent queues.

Dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT); // Dispatch_async (queue, ^{//.... Asynchronous task 1}); dispatch_async(queue, ^{ //.... Asynchronous task 2}); Dispatch_barrier_async (queue, ^{//... });Copy the code

A Dispatch barrier allows the creation of a synchronization point in a concurrent queue. When a barrier is encountered in a concurrent queue, it delays execution of the barrier’s block until all blocks submitted before the barrier have finished. At this point, the Barrier Block starts executing itself. After that, the queue continues to perform operations normally.

  • Queue group

After all the tasks in a certain queue are complete, other tasks can be executed

Dispatch_queue_t queue = dispatch_get_global_queue(0, 0); Dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ //... Asynchronous task 1}); dispatch_group_async(group, queue, ^{ //... Asynchronous task 2}); dispatch_group_async(group, queue, ^{ //... Asynchronous task 3}); Dispatch_group_notify (group, queue, ^{//... . });Copy the code

For example, load multiple images

// Use the Dispatch Group to append blocks to the Global Group Queue. If all of these blocks are executed, the end-of-processing block in the Main Dispatch Queue will be executed. Dispatch_group_t group = dispatch_group_create(); Dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); Dispatch_group_async (group, queue, ^{/* load picture 1 */}); Dispatch_group_async (group, queue, ^{/* load picture 2 */}); Dispatch_group_async (group, queue, ^{/* load picture 3 */}); // Group_notify (group, dispatch_get_main_queue(), ^{// merge image});Copy the code
  • Timing task
Dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); /* dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)); /* Set timer interval 5s */ dispatch_source_set_timer(_timer, when, 5.0 * NSEC_PER_SEC, 0); /* Timer callback block */ dispatch_source_set_event_handler(_timer, ^{// do something NSLog(@" Task to do!") ); }); /* Start timer */ dispatch_resume(_timer); self.timer = _timer; // Strong reference timer object (must)Copy the code

You must destroy self.timer to terminate a timed task: self.timer = nil;

GCD cancels the thread

You can cancel threads that have not yet executed. But there is no way to cancel a thread that is executing.

  • Cancel the dispatch_block_cancel function
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); dispatch_block_t block1 = dispatch_block_create(0, ^{ NSLog(@"block1"); }); dispatch_block_t block2 = dispatch_block_create(0, ^{ NSLog(@"block2"); }); dispatch_block_t block3 = dispatch_block_create(0, ^{ NSLog(@"block3"); }); dispatch_async(queue, block1); dispatch_async(queue, block2); dispatch_async(queue, block3); dispatch_block_cancel(block3); / / cancel block3Copy the code

Opportunistic: Use temporary variables + return to cancel the Block in progress.

__block BOOL gcdFlag = NO; // dispatch_async(dispatch_get_global_queue(0, 0), ^{for (long I =0; i<1000; I ++) {NSLog(@" doing the I :%ld", I); Sleep (0.1); If (gcdFlag==YES) {// Judge and terminate NSLog(@" terminate "); return ; }}; }); Dispatch_after (dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSLog(@" I'm going to stop "); gcdFlag = YES; });Copy the code