I. Concept of GCD:

Grand Central Dispatch (GCD) is a multi-core programming solution developed by Apple. It is used to optimize applications to support multi-core processors and is based on thread mode to execute concurrent tasks.

Ii. Advantages of GCD:

  1. Multiple cores are used for parallel computing
  2. GCD automatically makes full use of the device’s CPU core
  3. GCD automatically manages thread lifecycle (thread creation, thread scheduling, thread destruction)
  4. Using a simple

Tasks and queues in GCD

1. Tasks are operations that require GCD processing, i.e., code that requires multithreading.

There are two types of tasks: synchronous execution and asynchronous execution

Synchronous execution: It can only be executed in the current thread. It does not have the ability to start a new thread. It waits and executes in order

Asynchronous execution: New threads can be started and executed concurrently. You do not need to wait for the task to finish before continuing other operations

2. Queue is the waiting queue for the task to be executed. It is a special linear table that adopts the first-in, first-out principle

There are two types of queues: serial queues and concurrent queues. The main difference between the two is the order of execution and the ability to start new threads

  1. Serial queues: Only one task is scheduled at a time. The next task is scheduled until the last task is completed
  2. Concurrent queue: Dispatching multiple tasks simultaneously

3.GCD usage steps:

  1. Create a task queue (serial queue, concurrent queue)
  2. Add the task to the created wait queue and specify the execution type of the task (asynchronous, synchronous)

4. How to create and obtain a queue:

  1. Serial and parallel queues

    /* * @param Label Unique identifier of the queue, used for DEBUG, can be null. The name of the queue is recommended to use the application ID in reverse order. * @param attr set to serial queue or concurrent queue */ // dispatch_queuE_CREATE (const char *_Nullable) label,dispatch_queue_attr_t _Nullable attr); // Dispatch_queue = dispatch_queue_create("q1", DISPATCH_QUEUE_SERIAL); Dispatch_queue_t queue2 = dispatch_queue_create("q2", DISPATCH_QUEUE_CONCURRENT);Copy the code
  2. Main Dispatch Queue

    All tasks in the main queue are scheduled for execution on the main thread

    dispatch_queue_t q = dispatch_get_main_queue();
    Copy the code
  3. Global Dispatch Queue

    /* * @param Identifier (default: DISPATCH_QUEUE_PRIORITY_DEFAULT) * @param flags Queue identifier (default: DISPATCH_QUEUE_PRIORITY_DEFAULT) 0) */ //dispatch_get_global_queue(intPtr_t identifier, uintPtr_t flags); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);Copy the code

    Note: Global queue asynchronous operations create multiple threads and execute without order

5. Task creation method:

{dispatch_sync(queue, ^{// put the task code for synchronous execution}); {dispatch_async(queue, ^{// put the async task code here});Copy the code
dispatch_queue_t queue1 = dispatch_queue_create("q1", DISPATCH_QUEUE_SERIAL); NSLog(@" synchronous serial %@",[NSThread currentThread]); }); Dispatch_async (dispate1, ^{// operation requires a child thread, will create a new thread, thread is created and regenerated, the operation sequence is executed, "the most safe choice" NSLog(@" asynchronous serial %@",[NSThread currentThread]); }); dispatch_queue_t queue2 = dispatch_queue_create("q2", DISPATCH_QUEUE_CONCURRENT); NSLog(@" synchronous parallel %@",[NSThread currentThread]); }); Dispatch_async (dispate2, ^{// dispatch_async(queue2, ^{/) { // If there are other tasks in front of the queue, the queue will wait until the previous task is completed. // Scenario: does not affect the main thread and does not require sequential operations! NSLog(@" %@",[NSThread currentThread]); });Copy the code

Note:

Calling Main queue + Synchronous execution in main thread causes deadlock problems. This is because the synchronization tasks appending to the main queue and the tasks of the main thread itself are waiting for each other, blocking the “main queue” and ultimately causing a deadlock in the thread (the main thread) where the main queue resides. If we call “main queue” + “Synchronous execution” in “other threads”, we will not block “main queue” and will not cause deadlock problems. The end result: no new threads are started, and tasks are executed sequentially.

6. Semaphore

The wait function reduces the semaphore by 1, and the signal function increases the semaphore by 1. If the semaphore is less than 0, the current thread is blocked. You can also control the amount of concurrent threads through semaphores.

Dispatch_queue_queue = dispatch_queue_create("q1", DISPATCH_QUEUE_CONCURRENT); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_async(concurrentQueue, ^{ sleep(2); NSLog(@"async1... %@",[NSThread currentThread]); **dispatch_semaphore_signal(semaphore); * *}); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_async(concurrentQueue, ^{ sleep(2); NSLog(@"async2... %@",[NSThread currentThread]); **dispatch_semaphore_signal(semaphore); * *}); **dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); ** dispatch_async(concurrentQueue, ^{ sleep(2); NSLog(@"async3... %@",[NSThread currentThread]); });Copy the code

7. Barriers

The fence function in GCD is always used to make the task before the fence in the queue execute first, then execute the fence task, and then execute the task after the fence, so as to achieve multi-threaded synchronization. The fence function functions like a pthread_rwLOCK_WRLOCK read/write lock.

Note: 1. There are synchronous barriers (dispatch_barrier_sync) and asynchronous barriers (dispatch_barrier_async). The difference is that synchronous barriers block the current thread, similar to dispatch_sync, asynchronous barriers do not block the current thread. 2. Concurrent queues should be created manually using the dispatch_queue_create function. If the queue passed to this function is a serial queue or a global concurrent queue, this function will behave similar to the dispatch_async function.

dispatch_queue_t concurrentQueue = dispatch_queue_create("q1", DISPATCH_QUEUE_CONCURRENT); dispatch_async(concurrentQueue, ^{ sleep(2); NSLog(@"async1... %@",[NSThread currentThread]); }); dispatch_async(concurrentQueue, ^{ sleep(2); NSLog(@"async1... %@",[NSThread currentThread]); }); dispatch_barrier_async(concurrentQueue, ^{ sleep(2); NSLog(@"async2... %@",[NSThread currentThread]); }); dspatch_async(concurrentQueue, ^{ sleep(2); NSLog(@"async3... %@",[NSThread currentThread]); }); dispatch_async(concurrentQueue, ^{ sleep(2); NSLog(@"async3... %@",[NSThread currentThread]); });Copy the code