1. Basic Concepts
Process of 1.
- Is a program with independent functions, the basic unit of the operating system to allocate resources
- For example, if we open an iOS APP and it runs on the operating system, it becomes a process on the system (it can be multi-process on other platforms).
- Processes are independent of each other
Thread 2.
- Is the smallest unit used to perform a task
- A thread is an entity in a process. Threads make up a process
Thread and process relationship: Thread is the execution unit of a process. Threads in a process can share resources
Task 3.
- The section of code to execute in the thread.
- Mode of execution:
- Sync — Does not have the ability to open a thread, waits until the previous task is complete, and blocks the thread
- Async — The ability to start a thread and continue to perform tasks below the current one without waiting, without blocking the thread
4. The queue
- A queue is a common data structure, a special linear table. Features: first in, first out (FIFO principle).
- Role: to solve some task execution and waiting fairness, first served.
- Divided into serial queue and concurrent queue, both comply with FIFO(first in, first out) principle.
4.1. Serial queue:
- Tasks are executed one after another, and must wait for the previous task to complete before the next task can be executed. No matter how many threads enter the queue, they must queue to start.
4.2. Concurrent queue:
- Multiple tasks can be executed concurrently. The advantage of multithreading can be reappeared inside, high efficiency.
Comprehensive relationship: Tasks are executed through threads, which are the carrier of tasks. Tasks are sorted in queues for execution, and the execution of tasks is completed by threads opened by queues. And all of this is contained in the process, the smooth running of the process must rely on everyone to complete.
Here is a simple example diagram of a synchronization queue under a process:
Second, the common multithreading scheme in iOS
1. Enable the thread
- Pthreads (C) – Can be cross-platform, and the following three are based on pThreads
- NSThread(OC) – Makes threads operable, has thread objects, and the life cycle of a thread can be manually managed
- GCD(C) – Can make full use of multi-core equipment, automatic life cycle management
- NSOperation(OC) – Encapsulates THE GCD and is more object-oriented in use with automatic lifecycle management
2. Multi-threading mechanism:
2.1. Synchronous asynchronous function + serial parallel queue (p2 combination, four cases)
Question: Can you use asynchronous functions to enable multithreading?
A: No!
Reason: There are only two ways to enable threads in iOS:
1. Asynchronous + concurrent queue 2. Asynchronous + manually created serial queue
Special note: the main queue is a special serial queue, no matter what function with can not open multithreading
2.2 a deadlock
- Deadlock: Tasks wait for each other, causing threads to block
- Case: synchronous function + serial queue (deadlock if both conditions exist)
2.3. Thread safety
Threads can share resources, but this can cause some thread insecurity due to resource grabs.
To address thread-safety issues, we need to lock shared resources so that threads can access them in an orderly manner.
2.3.1. Types of common locks
Lock function: ensure the integrity of resources, you access, I can not access
- Exclusive locks:
- Simply ensure the integrity of the shared resource. Make sure I do it and you don’t do it
- @synchronized
- NSLock
- The spin lock.
- Much like a mutex, it does not rest when a resource is occupied, but keeps going around asking if it is available
- OSSpinLock:
- This works, but there is a priority inversion problem. If the waiting thread has a higher priority, it will continue to consume CPU (equivalent to executing a while loop), causing the lower level thread that originally holds the resource to be unable to release the lock and thus remain stuck
- Os_unfair_lock: Resolve the priority inversion problem
- Recursive lock:
- Prevents multiple locks in a thread from causing deadlocks. Scenario: Recursion
- NSRecursiveLock
- Semaphore:
- You can control the number of concurrent threads
- dispatch_semaphore_t
- Read and write locks:
- To separate the write from the read, such as our common fence function is the read and write lock
- dispatch_barrier_async / dispatch_barrier_sync
- Conditions of locks:
- Thread detectors decide whether to execute based on conditions
- NSCondition
- NSConditionLock
2.3.2. Control the execution order of threads
- Solution scenario: After tasks A, B, and C are complete, go to D
2.3.2.1. Semaphore
1.1. Signal creation
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
Copy the code
1.2. Waiting for signals: Make semaphore -1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); . Tasks to be performedCopy the code
1.3. Signal release: Let the amount of information +1 (threads that were waiting will execute one by one only if the semaphore value above is greater than or equal to 0)
. After the task is complete, dispatch_semaphoRE_signal (Semaphore) is generated.Copy the code
2.3.2.2. Fence function
Note:
1. The barrier function only makes sense for the concurrent queue created by itself. Do not use the global concurrent queue of the system, because this will block some system operations
2. Dispatch_barrier_sync: all operations with dispatch_barrier_sync will be blocked until it finishes, regardless of whether it is on the same queue or not!
Dispatch_barrier_async: will only give stuck down in the same queue operations, written under the function of other queue operations are not affected
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT); Dispatch_async (queue, ^{NSLog(@" start task A"); [NSThread sleepForTimeInterval:1]; NSLog(@" task A finish. }); Dispatch_async (queue, ^{NSLog(@" start task B")); [NSThread sleepForTimeInterval: 0.5]; NSLog(@" Task B finish "); }); Dispatch_async (queue, ^{NSLog(@" start task C")); [NSThread sleepForTimeInterval: 0.2]; NSLog(@" task C finish "); }); dispatch_barrier_async(queue, ^{ NSLog(@"============ barrier ==========="); }); Dispatch_async (queue, ^{NSLog(@" start task D")); [NSThread sleepForTimeInterval: 0.2]; NSLog(@" task D finish "); });Copy the code
2.3.2.3. Dispatch_group
- Create group dispatch_group_create()
- Enter the group: dispatch_group_enter (group)
- Leave the group: dispatch_group_leave (group)
- When all tasks are complete, callback: dispatch_group_notify()
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT); dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); Dispatch_async (queue, ^{NSLog(@" start task A"); [NSThread sleepForTimeInterval:3]; NSLog(@" task A finish. dispatch_group_leave(group); }); dispatch_group_enter(group); Dispatch_async (queue, ^{NSLog(@" start task B")); [NSThread sleepForTimeInterval:2]; NSLog(@" Task B finish "); dispatch_group_leave(group); }); dispatch_group_enter(group); Dispatch_async (queue, ^{NSLog(@" start task C")); [NSThread sleepForTimeInterval:1]; NSLog(@" task C finish "); dispatch_group_leave(group); }); Dispatch_group_notify (group, queue, ^{NSLog(@" start task D"); });Copy the code
2.3.2.4 NSBlockOperation dependence
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
// Create operation
NSBlockOperation *operationA=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"Perform 1st operation, thread: %@",[NSThread currentThread]);
}];
NSBlockOperation *operationB=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"Perform second operation, thread: %@",[NSThread currentThread]);
}];
NSBlockOperation *operationC=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"Perform 3rd operation, thread: %@",[NSThread currentThread]);
}];
NSBlockOperation *operationD=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"Perform 4th operation, thread: %@",[NSThread currentThread]);
}];
// Add dependencies
[operationA addDependency:operationB];
[operationB addDependency:operationC];
[operationC addDependency:operationD];
// Add the operation to the queue
[queue addOperation:operationA];
[queue addOperation:operationB];
[queue addOperation:operationC];
[queue addOperation:operationD];
Copy the code
Note:
1. If ABC tasks are executed in a sequential order, only semaphores, fence functions, and NSOperationQueue can be used
2. For the fence function, dispatch_barrier_async is used at the beginning of each task. If dispatch_async is not used, the task can be carried out in sequence