“This is the sixth day of my participation in the August More Text Challenge. For details, see: August More Text Challenge.”

Application of fence function

1. The concurrent fence function is asynchronous

- (void)concurrent_barrierAsync
{
    dispatch_queue_t concurrentQueue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    /* 1. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"1");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"2");
    });
    /* 2. */ // - dispatch_barrier_async
    dispatch_barrier_async(concurrentQueue, ^{
        NSLog(@"-- % @ -- -- -- -- --",[NSThread currentThread]);
    });
    /* 3. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"3");
    });
    / / 4
    NSLog(@"4");
}
Copy the code

Run print result

2. Concurrent fence function synchronization

- (void)concurrent_barrierSync
{
    dispatch_queue_t concurrentQueue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    /* 1. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"1");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"2");
    });
    /* 2. */ // - dispatch_barrier_sync
    dispatch_barrier_sync(concurrentQueue, ^{
        NSLog(@"-- % @ -- -- -- -- --",[NSThread currentThread]);
    });
    /* 3. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"3");
    });
    / / 4
    NSLog(@"4");
    
}
Copy the code

Run print result

3. The global queue fence function is asynchronous

- (void)global_barrierAsync
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(0.0);
    /* 1. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        sleep(1.5);
        NSLog(@"1");
    });
    dispatch_async(concurrentQueue, ^{
        sleep(1);
        NSLog(@"2");
    });
    /* 2. */ // - dispatch_barrier_async
    dispatch_barrier_async(concurrentQueue, ^{
        NSLog(@"-- % @ -- -- -- -- --",[NSThread currentThread]);
    });
    /* 3. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        sleep(0.5);
        NSLog(@"3");
    });
    / / 4
    NSLog(@"4");
}
Copy the code

Run print results concurrent disorder cannot use global queue

4. Global queue fence function synchronization

- (void)global_barrierSync
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(0.0);
    /* 1. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"1");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"2");
    });
    /* 2. */ // - dispatch_barrier_sync
    dispatch_barrier_sync(concurrentQueue, ^{
        NSLog(@"-- % @ -- -- -- -- --",[NSThread currentThread]);
    });
    /* 3. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"3");
    });
    / / 4
    NSLog(@"4");
    
}
Copy the code

Run the output concurrent 1 2 Run [NSThread currentThread] 4 3

5. The serial fence function is asynchronous

- (void)serial_barrierAsync
{
    dispatch_queue_t concurrentQueue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
    /* 1. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"1");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"2");
    });
    /* 2. */ // - dispatch_barrier_async
    dispatch_barrier_async(concurrentQueue, ^{
        NSLog(@"-- % @ -- -- -- -- --",[NSThread currentThread]);
    });
    /* 3. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"3");
    });
    / / 4
    NSLog(@"4");
}
Copy the code

The output is 4 unordered 1 2 [NSThread currentThread] 3 ordered

6. Serial fence function synchronization

- (void)serial_barrierSync
{
    dispatch_queue_t concurrentQueue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
    /* 1. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"1");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"2");
    });
    /* 2. */ // - dispatch_barrier_sync
    dispatch_barrier_sync(concurrentQueue, ^{
        NSLog(@"-- % @ -- -- -- -- --",[NSThread currentThread]);
    });
    /* 3. Asynchronous function */
    dispatch_async(concurrentQueue, ^{
        NSLog(@"3");
    });
    / / 4
    NSLog(@"4");
    
}
Copy the code

Run print result

The underlying principle of the fence function

Why does a fence function block the following code and control the flow? Let’s explore the rationale why we can use a custom concurrent queue and not a global queue

1.dispatch_barrier_sync

Enter the _dispatch_barrier_sync_f

Enter the _dispatch_barrier_sync_f_inline

Enter the _dispatch_sync_recurse

For a block callback to dispatch_barrier_sync, all tasks preceding dispatch_barrier_sync must be executed. Executing block means that there are no tasks in the current queue

Next let’s look at _dispatch_sync_invoke_and_complete_recurse

Next we go to _dispatch_sync_complete_recurse

Enter the dx_wakeup – > dq_wakeup

Serial and concurrencydq_wakeup->_dispatch_lane_wakeupGlobal queuedq_wakeup->_dispatch_root_queue_wakeup

Enter the _dispatch_lane_wakeup

Enter the_dispatch_lane_barrier_completethrough_dispatch_lane_drain_non_barriersThis put thebarrierskill

Enter _dispatch_lane_class_barrier_complete. All status is cleared

Global queue dq_wakeup->_dispatch_root_queue_wakeup there is no barrier processing

2.dispatch_barrier_async

Enter the_dispatch_continuation_async

Enter the dx_push – > dq_push

Concurrent access to _dispatch_LANe_concurrent_push

barrierEnter the_dispatch_lane_push

Then go through the synchronized flowdx_wakeup->dq_wakeup

Three. Semaphore use

  • Dispatch_semaphore_create Creates a semaphore
  • Dispatch_semaphore_wait Indicates that the semaphore is waiting
  • Dispatch_semaphore_signal Indicates that a semaphore is released
  dispatch_queue_t queue = dispatch_get_global_queue(0.0);
    dispatch_semaphore_t sem = dispatch_semaphore_create(1);
    1 / / task
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); / / wait for
        NSLog(@"Carry out Mission 1");
        NSLog(@"Mission 1 completed");
        dispatch_semaphore_signal(sem); / / signal
    });
    
    2 / / task
    dispatch_async(queue, ^{
        sleep(2);
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); / / wait for
        NSLog(@"Go to Mission 2");
        NSLog(@"Mission 2 completed");
        dispatch_semaphore_signal(sem); / / signal
    });
    
    3 / / task
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
        sleep(1);

        NSLog(@"Go to Mission 3");
        NSLog(@"Mission 3 completed"); dispatch_semaphore_signal(sem); }); Print the result2021-08-14 17:13:51.790864+0800 006-- Maximum number of concurrent GCD [37192:1201311[on a mission]1
2021-08-14 17:13:51.791029+0800 006-- Maximum number of concurrent GCD [37192:1201311] task1complete2021-08-14 17:13:52.793637+0800 006-- Maximum number of concurrent GCD [37192:1201313[on a mission]3
2021-08-14 17:13:52.794132+0800 006-- Maximum number of concurrent GCD [37192:1201313] task3complete2021-08-14 17:13:53.794370+0800 006-- Maximum number of concurrent GCD [37192:1201309[on a mission]2
2021-08-14 17:13:53.794940+0800 006-- Maximum number of concurrent GCD [37192:1201309] task2completeCopy the code
dispatch_queue_t queue = dispatch_get_global_queue(0.0);
    dispatch_semaphore_t sem = dispatch_semaphore_create(2);
    1 / / task
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); / / wait for
        sleep(0.5);
        NSLog(@"Carry out Mission 1");
        NSLog(@"Mission 1 completed");
        dispatch_semaphore_signal(sem); / / signal
    });
    2 / / task
    dispatch_async(queue, ^{
        sleep(0.5);
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); / / wait for
        NSLog(@"Go to Mission 2");
        NSLog(@"Mission 2 completed");
        dispatch_semaphore_signal(sem); / / signal
    });
    3 / / task
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
        sleep(0.5);

        NSLog(@"Go to Mission 3");
        NSLog(@"Mission 3 completed");
        dispatch_semaphore_signal(sem);
    });
    / / task 4
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
        sleep(0.5);
        NSLog(@"Go to Mission 4");
        NSLog(@"Mission 4 completed"); dispatch_semaphore_signal(sem); }); Print the result2021-08-14 17:16:37.592382+0800 006-- Maximum number of concurrent GCD [37213:1203700[on a mission]1
2021-08-14 17:16:37.592394+0800 006-- Maximum number of concurrent GCD [37213:1203701[on a mission]3
2021-08-14 17:16:37.592519+0800 006-- Maximum number of concurrent GCD [37213:1203701] task3complete2021-08-14 17:16:37.592519+0800 006-- Maximum number of concurrent GCD [37213:1203700] task1complete2021-08-14 17:16:37.592673+0800 006-- Maximum number of concurrent GCD [37213:1203702[on a mission]2
2021-08-14 17:16:37.592699+0800 006-- Maximum number of concurrent GCD [37213:1203704[on a mission]4
2021-08-14 17:16:37.592799+0800 006-- Maximum number of concurrent GCD [37213:1203702] task2complete2021-08-14 17:16:37.592839+0800 006-- Maximum number of concurrent GCD [37213:1203704] task4completeCopy the code

Dispatch_semaphore_create Controls the maximum number of concurrent requests

dispatch_queue_t queue = dispatch_get_global_queue(0.0);
dispatch_semaphore_t sem = dispatch_semaphore_create(0);

dispatch_async(queue, ^{
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); / / wait for
    sleep(3);
    NSLog(@"Carry out Mission 1");
    NSLog(@"Mission 1 completed");
});

dispatch_async(queue, ^{
    sleep(3);
    NSLog(@"Go to Mission 2");
    NSLog(@"Mission 2 completed");
    dispatch_semaphore_signal(sem); / / signal}); Print the result2021-08-14 20:58:18.699219+0800 006-- Maximum number of concurrent GCD [37635:1299035[on a mission]2
2021-08-14 20:58:18.699519+0800 006-- Maximum number of concurrent GCD [37635:1299035] task2complete2021-08-14 20:58:21.700031+0800 006-- Maximum number of concurrent GCD [37635:1299030[on a mission]1
2021-08-14 20:58:21.700493+0800 006-- Maximum number of concurrent GCD [37635:1299030] task1completeCopy the code

Dispatch_semaphore_wait Dispatch_semaphore_signal dispatch_semaphore_signal dispatch_semaphore_signal dispatch_semaphore_signal dispatch_semaphore_signal Dispatch_semaphore_signal

4. Semaphore principle

What’s going on at the bottom of the dispatch_semaphore_signal

1.dispatch_semaphore_wait

If you createdispatch_semaphore_t sem = dispatch_semaphore_create(0)

0-1 = -1 Go to _dispatch_semaphore_wait_slow

Enter the_dispatch_sema4_wait

ret == -1I have beendowhileThe loop is stuck here

So should first execute another thread first execute dispatch_semaphore_signal before execute dispatch_semaphore_wait if create dispatch_semaphore_t sem = dispatch_semaphore_create(0)

0 + 1 = 1directlyreturnThen performdispatch_semaphore_wait 1-1 = 0directlyreturn

Five. Scheduling group application problems

  • dispatch_group_createCreate a group
  • dispatch_group_asyncInto a set of tasks
  • dispatch_group_notifyNotification of completion of a group task
  • dispatch_group_wait Waiting time for group task execution
  • dispatch_group_enterInto the group
  • dispatch_group_leaveA set of
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0.0);
dispatch_group_async(group, queue, ^{
    // Create a scheduling group
    [self.mArray addObject:@"1"];
});
dispatch_group_async(group, queue, ^{
    [self.mArray addObject:@"2"];
    
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
   NSLog(@"Array = % @",self.mArray); }); Print the result2021-08-14 22:37:22.112900+0800 005-- Advanced use of GCD (2)[38331:1372252] array = (1.2
)
Copy the code
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0.0);
dispatch_group_async(group, queue, ^{
    // Create a scheduling group
    [self.mArray addObject:@"1"];
});
dispatch_group_async(group, queue, ^{
    [self.mArray addObject:@"2"];
    
});
// Enter and exit in pairs
dispatch_group_enter(group);
dispatch_async(queue, ^{
    [self.mArray addObject:@"3"];
    dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
   NSLog(@"Array = % @",self.mArray); }); Print the result2021-08-14 22:40:15.258917+0800 005-- Advanced use of GCD (2)[38364:1375249] array = (1.2.3
)
Copy the code

Principles of scheduling groups

  • Why the crash happened when the order of group in and group out was reversed
  • Why the synchronization effect
  • dispatch_group_async = dispatch_group_enter + dispatch_group_leave

1.dispatch_group_create

Going to _dispatch_group_CREATE_with_count is different than the initialization of the semaphore

2.dispatch_group_enter

0 - > 1 3.dispatch_group_leave

1 - > 0Wake up thedispatch_group_notifyContinue to perform

4.dispatch_group_async

Enter the_dispatch_continuation_group_async

Enter the_dispatch_continuation_async

Enter the dx_push – > dq_push

Enter the _dispatch_root_queue_push

Enter the_dispatch_root_queue_push_inline

Enter the _dispatch_root_queue_poke

Enter the_dispatch_root_queue_poke_slow

Enter the_dispatch_root_queues_init

Enter the_dispatch_root_queues_init_once

Enter the _dispatch_worker_thread2

Enter the _dispatch_root_queue_drain

Enter the _dispatch_continuation_pop_inline

Enter the _dispatch_continuation_invoke_inline

Enter the_dispatch_continuation_with_group_invoke

Seven dispatch_source.

  • dispatch_source_createCreate the source
  • dispatch_source_set_event_handlerSet the source callback event
  • dispatch_source_merge_dataSource event Settings data
  • dispatch_source_get_dataObtain the event source data
  • dispatch_resumeContinue to
  • dispatch_suspendhang
 __block int timeout=10; // Countdown time
      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0.0,queue);
      dispatch_source_set_timer(self.timer ,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); // Execute per second
      dispatch_source_set_event_handler(self.timer, ^{
          if(timeout<=0) {// Close the countdown
              dispatch_source_cancel(self.timer);
              dispatch_async(dispatch_get_main_queue(), ^{
                  // The button in the setting interface is displayed according to your own requirements
                  NSLog(@"The timer stop");
               
              });
          }else{
              int minutes = timeout / 60;
              int seconds = timeout % 60;
              NSString *strTime = [NSString stringWithFormat:@"%d minutes %.2d seconds to re-obtain the verification code",minutes, seconds];
              dispatch_async(dispatch_get_main_queue(), ^{
                  // The button in the setting interface is displayed according to your own requirements
                  NSLog(@"% @",strTime); }); timeout--; }});// Restore the startup
    dispatch_resume(self.timer);
    / / hung
    dispatch_suspend(self.timer);
Copy the code

Variable array insecurity analysis

  dispatch_queue_t concurrentQueue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    // Multithreaded marray
    for (int i = 0; i<1000; i++) {
        dispatch_async(concurrentQueue, ^{
            NSString *imageName = [NSString stringWithFormat:@"%d.jpg", (i % 10)];
            NSURL *url = [[NSBundle mainBundle] URLForResource:imageName withExtension:nil];
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *image = [UIImage imageWithData:data];
            [self.mArray addObject:image];

        });
    }
Copy the code

The reason for the crash is that the thread is not safe. Self. MArray’s continuous read-write operation is releasing the old value and releasing the new value To make it safe you need to lock it or add dispatch_barrier_async

  dispatch_queue_t concurrentQueue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    // Multithreaded marray
    for (int i = 0; i<1000; i++) {
        dispatch_async(concurrentQueue, ^{
            NSString *imageName = [NSString stringWithFormat:@"%d.jpg", (i % 10)];
            NSURL *url = [[NSBundle mainBundle] URLForResource:imageName withExtension:nil];
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *image = [UIImage imageWithData:data];
            dispatch_barrier_async(concurrentQueue , ^{
                [self.mArray addObject:image];
            });

        });
    }
Copy the code