Painted painted levels: fostered fostered fostered

Tags: “iOS” “Multi-threading” “GCD” author: Dac_1033 Review: QiShare team

I. Introduction to THE COMMUNIST Party of China

Grand Central Dispatch(GCD) is a multi-threaded scheduling framework developed by Apple that optimizes the execution of multi-threaded applications to support multi-core processors. GCD has thread pools at the bottom. The concept of thread pools was briefly introduced in the previous article. Thread pools are automatically maintained by the system, and developers only focus on the creation of Dispatch queues and tasks and synchronous asynchronous calls. Implementing threading with GCD in iOS is simple: Create a queue > synchronous/asynchronous call > place the task in the block of the previous call. When the time-consuming operation is completed, return to the main thread to update the corresponding UI function. The simple code is as follows:

dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_CONCURRENT); ^{dispatch_async(dispatch_get_main_queue()) ^{ Update UI Update UI can only be updated in the main thread}); });Copy the code

When the method in GCD is called to perform multi-threaded operations, GCD can automatically use the CPU’s multi-core to achieve asynchronous processing tasks, automatic management of thread life cycle (create thread, schedule task, destroy thread), developers only need to set the task that GCD needs to execute, do not need to write any thread management code. Therefore, GCD is the most recommended multithreading framework for developers.

Ii. Details of the COMMUNIST Party of China

First, we use GCD to load multiple network pictures asynchronously. Let’s get familiar with the process of using GCD:

//// 图 文 Model @interface GCDImage: nSObject@property (nonatomic, assign) NSInteger index; @property (nonatomic, strong) NSData *imgData; @end @implementation GCDImage @end //// GCD #define ColumnCount 4 #define RowCount 5 #define Margin 10 @interface MultiThread_GCD () @property (nonatomic, strong) NSMutableArray *imageViews; @end @implementation MultiThread_GCD - (void)viewDidLoad { [super viewDidLoad]; [self setTitle:@"GCD"]; [self.view setBackgroundColor:[UIColor whiteColor]]; self.edgesForExtendedLayout = UIRectEdgeNone; [self layoutViews]; } - (void)layoutViews { CGSize size = self.view.frame.size; CGFloat imgWidth = (size.width - Margin * (ColumnCount + 1)) / ColumnCount; _imageViews=[NSMutableArray array]; for (int row=0; row<RowCount; row++) { for (int colomn=0; colomn<ColumnCount; colomn++) { UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(Margin + colomn * (imgWidth + Margin), Margin + row * (imgWidth + Margin), imgWidth, imgWidth)]; imageView.backgroundColor = [UIColor cyanColor]; [self.view addSubview:imageView]; [_imageViews addObject:imageView]; } } UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; button.frame = CGRectMake(15, (imgWidth + Margin) * RowCount + Margin, size.width - 15 * 2, 45); [button addTarget:self action:@selector(loadImageWithMultiOperation) forControlEvents:UIControlEventTouchUpInside]; [button setTitle: @ "click load" forState: UIControlStateNormal]; [self.view addSubview:button]; } # pragma mark - multi-threaded download images / / - (void) loadImageWithMultiOperation {/ / / / int count = RowCount * ColumnCount; // // // Create a serial queue. First parameter: queue name second parameter: Queue type // // Note that the queue object is not a pointer. // dispatch_queue_t serialQueue=dispatch_queue_create("QiShareSerialQueue", DISPATCH_QUEUE_SERIAL); // // create multiple threads to fill images // for (int I =0; i<count; ++ I) {// // dispatch_async(serialQueue, ^{// GCDImage *gcdImg = [[GCDImage alloc] init]; // gcdImg.index = i; // [self loadImg:gcdImg]; / /}); // // } //} - (void)loadImageWithMultiOperation { int count = RowCount * ColumnCount; // Get the first argument: thread priority Dispatch_queue_t globalQueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); For (int I =0; i<count; ++ I) {dispatch_sync(globalQueue, ^{GCDImage *gcdImg = [[GCDImage alloc] init]; gcdImg.index = i; [self loadImg:gcdImg]; }); ImgData = [self requestData]; // dispatch_sync(dispatch_get_main_queue(), ^{[self updateImage:gcdImg]; / /}); // Print the current thread NSLog(@"current thread: %@", [NSThread currentThread]); } #pragma mark - (NSData *)requestData {NSURL *url = [NSURL *url URLWithString:@"https://store.storeimages.cdn-apple.com/8756/as-images.apple.com/is/image/AppleInc/aos/published/images/ A/pp/apple/products/apple - products - section1 - one - holiday - 201811? Wid = 2560 & hei = 1046 & FMT = jpeg&qlt = 95 & op_usm = 0.5, 0.5 &. V = 15405 76114151 "]; NSData *data = [NSData dataWithContentsOfURL:url]; return data; } #pragma mark - (void)updateImage:(GCDImage *)gcdImg {UIImage *image = [UIImage imageWithData:gcdImg.imgData]; UIImageView *imageView = _imageViews[gcdImg.index]; imageView.image = image; } @endCopy the code

Let’s take a step-by-step look at the details of GCD…

2.1 Common methods used to perform tasks in GCD
(dispatch_queue_t queue, dispatch_block_t block); Dispatch_async (dispatch_queue_t queue, dispatch_block_t block);Copy the code

Where, the first parameter is the queue to which the task is to join. The second argument is a block of type dispatch_block_T, which is a task (a piece of code).

2.2 Queues in the GCD
Dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_SERIAL); Dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_CONCURRENT);Copy the code

The first parameter is the name of the queue. The second parameter is named according to the value, which is the type of the queue.

Two special queues:

  • Main Dispatch Queue: a serial Queue. All tasks in the Main Queue are executed in the Main thread.

Dispatch_queue_t queue = dispatch_get_main_queue();

  • Global Dispatch Queue: yes and issue Queue;

Dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); The first parameter is the queue priority. DISPATCH_QUEUE_PRIORITY_DEFAULT is usually used. The second argument is 0.

The combination of the scheduling method and the queue where the task resides is as follows:

Scheduling method Concurrent queue Serial queues The home side column
Asynchronous (dispatch_async) Start multiple new threads to execute tasks concurrently Start a new thread to execute tasks in sequence No new thread is started and the task is executed sequentially
Synchronization (dispatch_sync) No new thread is started and the task is executed sequentially No new thread is started and the task is executed sequentially Main thread call: a deadlock causes the program to freeze

Other thread calls: No new thread is opened, the task is executed sequentially

We can verify the correctness of each of the above list combinations by running the following code:

- (void)addTask:(NSInteger)tag { [NSThread sleepForTimeInterval:2]; NSLog(@"addTask%ld--->> %@", (long)tag, [NSThread currentThread]); NSURLSessionTask *task = [NSURLSession.sharedSession dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.so.com/"]] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {NSLog(@" task completed %ld-- >> %@", (long)tag, [NSThread currentThread]);}]; [task resume]; } #pragma mark - serial/concurrent queue + synchronous/asynchronous call combination // asynchronous execution - (void)asyncExecute {NSLog(@"CurrentThread-- %@", [NSThread currentThread]); NSLog(@"asyncExecute start"); // dispatch_queue_t queue = dispatch_queue_create(QiShareQueue, DISPATCH_QUEUE_CONCURRENT); // // + serial queue (dispatch_queue_t queue = dispatch_queue_create(QiShareQueue, DISPATCH_QUEUE_SERIAL); // // + main queue(dispatch_queue_t queue = dispatch_get_main_queue(); for (NSInteger i=0; i<10; I ++) {dispatch_async(queue, ^{// addTask: I]; }); } NSLog(@"asyncExecute end"); } - (void)syncExecute {NSLog(@"currentThread-- %@", [NSThread currentThread]); NSLog(@"syncExecute start"); // // + concurrent queue (no new thread is opened and tasks are executed sequently) // dispatch_queue_t queue = dispatch_queue_create(QiShareQueue, DISPATCH_QUEUE_CONCURRENT);  // // + serial queue (dispatch_queue_t queue = dispatch_queue_create(QiShareQueue, DISPATCH_QUEUE_SERIAL); // + main queue (1. Dispatch_queue_t queue = dispatch_get_main_queue(); for (NSInteger i=0; i<10; I ++) {dispatch_sync(queue, ^{// addTask [self addTask: I]; }); } NSLog(@"syncExecute end"); }Copy the code
2.3 Communication between GCD threads

For example, after performing an operation asynchronously from a non-main thread, we can go back to the main thread to update the UI roughly as follows:

Dispatch_async (dispatch_get_global_queue(0, 0), ^{dispatch_async(dispatch_get_main_queue()), ^{// update UI}); });Copy the code
2.4 About GCD deadlock

In the main thread, execute the following code directly:

dispatch_sync(dispatch_get_main_queue(), ^{
   
});
Copy the code

The interface freezes and a GCD deadlock occurs. The reason is that the main thread is performing a dispatch_sync operation (synchronizing and waiting for the block to complete), whereas the dispatch_sync operation is waiting for the main thread to complete the current operation before adding the block to the main queue, thus creating a “mutual wait”. Normally, if a thread is in the process of executing a task on the serial queue sQueue, calling dispatch_sync again will cause a deadlock as follows:

- (void)deadLock { dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_SERIAL); NSLog(@"1"); dispatch_async(queue, ^{ NSLog(@"2"); dispatch_sync(queue, ^{ NSLog(@"3"); }); }); NSLog(@"4"); } //// print log (interface is dead) //2019-01-14 18:07:22.161085+0800 QiMultiThread[469:47692] 1 QiMultiThread[469:47692] 4 //2019-01-14 18:07:22.161346+0800 QiMultiThread[469:47707] 2Copy the code

Other common methods in GCD

3.1 dispatch_once

It is generally used to create a singleton and place the instantiation part of a class in a block of dispatch_once.

static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // code to be executed once
    })
Copy the code
3.2 dispatch_after

In a queue, delay execution of an action, such as app startup first, start screen animation, delay loading interface, etc.

dispatch_queue_t queue= dispatch_get_main_queue(); Dispatch_after (dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{ });Copy the code
3.3 dispatch_apply

A specified task (that is, block) in a queue can be executed n times with the dispatch_apply method.

dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_CONCURRENT); Dispatch_apply (10, queue, ^(size_t I) {NSLog(@" execute %lu ", (long) I); });Copy the code

Note: if the queue is a concurrent queue, the block task is executed concurrently. Dispatch_apply is a synchronous call and the block task is executed n times before returning.

3.4 dispatch_barrier

There are two methods for dispatch_barrier: dispatch_barrier_async and dispatch_barrier_sync. The dispatch_barrier method on the same queue waits for all its previous tasks to complete before executing itself, and then executing its subsequent tasks.

-(void)diapatchBarrier { NSLog(@"currentThread: %@", [NSThread currentThread]); NSLog(@"---start---"); dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:7]; NSLog(@"asyncTask_1"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:5]; NSLog(@"asyncTask_2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"barrier_asyncTask"); [NSThread sleepForTimeInterval:3]; }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"asyncTask_4"); }); NSLog(@"---end---"); } //// Displays logs //2019-01-14 16:56:40.673822+0800 QiMultiThread[401:32253] currentThread: <NSThread: 0x1c42622c0>{number = 1, Name = main} //2019-01-14 16:56:40.674137+0800 QiMultiThread[401:32253] --start-- //2019-01-14 16:56:40.674364+0800 QiMultiThread[401:32253] --end-- //2019-01-14 16:56:45 //2019-01-14 [401:32340] asyncTask_2 [401:32285] QiMultiThread[401:32285] QiMultiThread[401:32285] //2019-01-14 16:56:51.688996+0800 QiMultiThread[401:32285] asyncTask_4Copy the code
3.5 dispatch_group

In A serial queue, if you want task A to be executed after A series of other tasks B, C, and D are completed, you simply append task A to the series of tasks in the serial queue. But in parallel queues, dispatch_group is needed for this wave operation.

1) Dispatch_group_notify Because dispatch_group_notify is executed asynchronously, it does not block the current thread.

-(void)dispatchGroupNotify { NSLog(@"currentThread: %@", [NSThread currentThread]); NSLog(@"---start---"); dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"groupTask_1"); NSLog(@"currentThread: %@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:7]; NSLog(@"groupTask_2"); NSLog(@"currentThread: %@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:4]; NSLog(@"groupTask_3"); NSLog(@"currentThread: %@", [NSThread currentThread]); }); dispatch_group_notify(group, queue, ^{ NSLog(@"dispatch_group_Notify block end"); }); NSLog(@"---end---"); } //// Print log //2019-01-14 15:21:15.194094+0800 QiMultiThread[295:9717] --start-- //2019-01-14 15:21:15.194270+0800 QiMultiThread[295:9717] --end-- //2019-01-14 15:21:17.20617 +0800 QiMultiThread[295:9820] groupTask_1 //2019-01-14 15:21:17. 199424 + 0800 QiMultiThread [295-9820] currentThread: < NSThread: 0x1c4660640>{number = 3, Name = (null)} //2019-01-14 15:21:19.200911+0800 groupTask_3 //2019-01-14 15:21:19.201224+0800 QiMultiThread[295:9825] currentThread: <NSThread: 0x1c0278640>{number = 4, Name = (null)} //2019-01-14 15:21:22.200290+0800 groupTask_2 //2019-01-14 15:21:22.200595+0800 QiMultiThread[295:9745] currentThread: <NSThread: 0x1c4666b00>{number = 5, Name = (NULL)} //2019-01-14 15:21:22.200810+0800 QiMultiThread[295:9745] dispatch_group_Notify endCopy the code

2) dispatch_group_wait as the name implies, dispatch_group_wait blocks the current thread until all tasks are completed.

-(void)dispatchGroupWait { NSLog(@"currentThread: %@", [NSThread currentThread]); NSLog(@"---start---"); dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"groupTask_1"); NSLog(@"currentThread: %@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:7]; NSLog(@"groupTask_2"); NSLog(@"currentThread: %@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:4]; NSLog(@"groupTask_3"); NSLog(@"currentThread: %@", [NSThread currentThread]); }); long result = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC)); NSLog(@"dispatch_group_wait result = %ld", result); NSLog(@"---end---"); } //// print log //2019-01-14 15:46:37.226768+0800 QiMultiThread[323:15757] --start-- //2019-01-14 15:46:39.231152+0800 QiMultiThread[323:15795] groupTask_1 //2019-01-14 15:46:39.231367+0800 QiMultiThread[323:15795] currentThread <NSThread: 0x1c0073600>{number = 3, Name = (null)} //2019-01-14 15:46:41.232170+0800 QiMultiThread[323:15801] groupTask_3 //2019-01-14 15:46:41.232644+0800 QiMultiThread[323:15801] currentThread: <NSThread: 0x1c00736c0>{number = 4, Name = (null)} //2019-01-14 15:46:44.231956+0800 QiMultiThread[323:15827] groupTask_2 //2019-01-14 15:46:44.232328+0800 QiMultiThread[323:15827] currentThread: <NSThread: 0x1c446b440>{number = 5, Name = (null)} //2019-01-14 15:46:44.232468+0800 QiMultiThread[323:15757] dispatch_group_wait result = 0 //2019-01-14 15:46:44. 232525 + 0800 QiMultiThread (323-15757) -- -- -- end -- -- -Copy the code

Note: Dispatch_group_wait is set to 10 seconds. If the execution time of all group tasks is <=10 seconds, 0 is returned. If the execution time of all group tasks is >10 seconds, non-0 is returned.

3) Dispatch_group_Enter and dispatch_group_leave use dispatch_group_Enter and dispatch_group_leave together with dispatch_async. Can be replaced with dispatch_group_async. The dispatch_group_enter and dispatch_group_leave methods need to be paired, and dispatch_group_notify is required at the end of the group operation.

-(void)dispatchGroupEnter { NSLog(@"currentThread: %@", [NSThread currentThread]); NSLog(@"---start---"); dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_group_enter(group); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:7]; NSLog(@"asyncTask_1"); dispatch_group_leave(group); }); dispatch_group_enter(group); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:4]; NSLog(@"asyncTask_2"); dispatch_group_leave(group); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"dispatch_group_notify block end"); }); NSLog(@"---end---"); CurrentThread [318:16283] currentThread: <NSThread: 0x1c007bc00>{number = 1, Name = main} //2019-01-14 15:47:56.819064+0800 QiMultiThread[318:16283] --start-- //2019-01-14 15:47:56.819122+0800 QiMultiThread[35:16283] --end-- //2019-01-14 15:48:00 +0800 QiMultiThread[35:16317] //2019-01-14 QiMultiThread[35:03.824189 +0800 QiMultiThread[35:03.824189] QiMultiThread[35:03.824189] dispatch_group_notify block endCopy the code
3.6 dispatch_block

The following two methods add a task to a queue:

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
Copy the code

We can define a separate dispatch_block_t variable for the second parameter and pass it into the corresponding method:

// define a separate dispatch_block_t block=dispatch_block_create(0, ^{NSLog(@"dispatchBlock_work"); }); // Call procedure dispatch_async(queue, block);Copy the code

1) Dispatch_block_wait The effect of dispatch_block_wait is similar to that of dispatch_group_wait and blocks the current thread. In the following code, the wait operation is performed in dispatch_async (queue of DISPATCH_QUEUE_CONCURRENT type), avoiding blocking the main thread.

- (void)dispatchBlockWait { dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_block_t block = dispatch_block_create(0, ^{ NSLog(@"---before---"); [NSThread sleepForTimeInterval:7]; NSLog(@"---after---"); }); dispatch_async(queue, block); dispatch_async(queue, ^{ long result = dispatch_block_wait(block, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC)); NSLog(@"dispatch_block_wait result = %ld", result); }); } //2019-01-14 16:34:59.389940+0800 QiMultiThread[382:27805] --before-- //2019-01-14 16:35:02.396144+0800 QiMultiThread[382:27809] dispatch_block_wait result = 49 //2019-01-14 16:35:06.395332+0800 QiMultiThread[382:27805] ---after---Copy the code

2) dispatch_block_notify Dispatch_block_notify When the execution of a block is completed, a specific block is immediately sent to the queue for execution. This function has three parameters. The first parameter is the block to be observed. The second argument is the queue to which the notified block is committed, and the third argument is the block to which the notified block should be executed

- (void)dispatchBlockNotify { //dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_block_t preBlock = dispatch_block_create(0, ^{ NSLog(@"preBlock start"); [NSThread sleepForTimeInterval:2]; NSLog(@"preBlock end"); }); dispatch_async(queue, preBlock); dispatch_block_t afterBlock = dispatch_block_create(0, ^{ NSLog(@"has been notifyed"); }); dispatch_block_notify(preBlock, queue, afterBlock); } //// print log //2019-01-14 17:20:33.893522+0800 QiMultiThread[425:37900] preBlock start //2019-01-14 17:20:35.898765+0800 QiMultiThread[425:37900] preBlock end //2019-01-14 17:20:35.899008+0800 QiMultiThread[425:37900] has been notifyedCopy the code

Note: queue is DISPATCH_QUEUE_SERIAL or DISPATCH_QUEUE_CONCURRENT. After a preBlock completes execution, afterBlock is automatically committed to a queue (which can be any other custom queue).

3) Dispatch_block_cancel blocks submitted to queues are undoable as follows

dispatch_block_t block = dispatch_block_create(0, ^{ }); dispatch_async(queue, block); dispatch_block_cancel(block); // Undo a taskCopy the code
3.7 dispatch_set_target_queue

The dispatch_set_target_queue function has two parameters queue and targetQueue. The dispatch_set_target_queue function has two functions: Priority of queue and targetQueue. TargetQueue has a higher priority. A targetQueue can be a reference queue for all tasks in the queue, that is, tasks in the queue will be executed according to the type characteristics of the targetQueue.

dispatch_set_target_queue(queue, targetQueue);
Copy the code

Synchronizing the execution of tasks in different queues:

- (void) dispatchSet2 { dispatch_queue_t targetQueue = dispatch_queue_create("QiShareQueue", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue1 = dispatch_queue_create("QiShareQueue_1", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue2 = dispatch_queue_create("QiShareQueue_2", DISPATCH_QUEUE_CONCURRENT); dispatch_set_target_queue(queue1, targetQueue); dispatch_set_target_queue(queue2, targetQueue); dispatch_async(queue1, ^{ [NSThread sleepForTimeInterval:5]; NSLog(@"Task_1"); }); dispatch_async(queue2, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"Task_2"); }); dispatch_async(queue2, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"Task_3"); }); } //// print log //2019-01-14 17:45:29.920351+0800 QiMultiThread[447:42950] currentThread: <NSThread: 0x1c407c600>{number = 1, Name = main} //2019-01-14 17:45:29.920424+0800 QiMultiThread[447:42950] --start-- //2019-01-14 17:45:29.920474+0800 QiMultiThread[45:42950] --end-- //2019-01-14 17:45:42987 +0800 QiMultiThread[45:42987] Task_1 //2019-01-14 17:45:37.930813+0800 QiMultiThread[45:42987] Task_3 //2019-01-14 17:45:42987 +0800 QiMultiThread[45:42987] Task_3Copy the code

In the above code, we set the targetQueue to serial, and queue1 and queue2 are executed according to the type characteristics of targetQueues.

ps:

  1. Although async has the ability to start a new thread, it does not necessarily start a new thread. Whether to start a new thread depends on the queue type of the task.
  2. In the dispatch_barrier_(a)sync method, we are careful not to use global concurrent queues; custom queues of type DISPATCH_QUEUE_CONCURRENT are more appropriate.

Reference article link, thanks!

Project source GitHub address


Recommended articles:

IOS Winding Rules iOS signature mechanism iOS Scan qr code/bar code iOS learn about Xcode Bitcode iOS Redraw drawRect odd dance weekly