preface
For multithreading I think is very important, the actual development of the use and the frequency of the interview is very high. The use of multiple threads will most likely involve GCD, so the next thread exploration will focus on GCD
1. Thread understanding
Let’s start with a few nouns
process
A process is an application that is running in the system. Each process has its own memory space and does not affect each other.thread
Threads are scheduled by the processorThe basic unit
A thread must depend on a process. In order for a process to perform a task, it must have a thread. The process must have at least one thread.multithreading
: in the iOSMultithreading simultaneous execution
Is the essence of the CPU in multiple tasks directly to quickly switch, due to the CPU scheduling thread time is fast enough, resulting in the effect of multi-threading “simultaneous” execution. Where the switching interval isTime slice
Each thread can perform only one task at a time.A single core CPU
.The CPU can only process one thread at a time
That is, only one thread is working.task
In other words, the piece of code that you execute in a thread. In GCD it is placed in a blockThe queue
: By one or moreThe task of
A special kind of linear table. When these tasks are ready to be executed, the system assigns them to a thread for execution.Queues and threads are two hierarchies
. Queues are abstract structures for ease of use and understanding, whileThreads are system level
The units of operation scheduling in the hierarchy.
2. The meaning of multithreading
- Advantages: can properly improve the execution efficiency of the program, can be appropriate
Improve resource utilization
(CPU, memory), the thread will be automatically destroyed after the task is completed. - Disadvantages: If open
Lots of threads
, will take up a lot of memory space,Reduce program performance
The more threads, the more overhead the CPU has on calling threads.
2.1 Queue and Synchronization Asynchronism
Serial queues
: Only one task is executed at a time. letThe tasks are carried out one after another
. (Only one thread is started. After one task is completed, the next task is executed.)Parallel lines
: Can be multipleTasks are executed concurrently
. (which can beStart multiple threads
And execute tasks simultaneously)synchronous
: Synchronously adds tasks to a specified queue. Before the added tasks are executed,Will always wait
, and continue to execute the next task until the task in the queue completes. Tasks can only be executed in the current thread,Does not have the ability to start new threads
, soBlocks the thread
.- Asynchronous: Asynchronously adds a task to a specified queue. It does not wait and can continue to execute the task. You can execute tasks in a new thread,
Ability to start new threads
.Doesn't block the thread
conclusion
Asynchrony starts a new thread. Asynchrony does not start a thread and only executes on the current thread. The queue itself has nothing to do with threads. Queues focus only on tasks. Serial queues execute tasks one after another. Parallel queues can execute multiple tasks simultaneously.
Text description is not really understood, so let’s look at the code below.
synchronous
Will not start a new thread,asynchronous
A new thread is opened
// Serial queue
dispatch_queue_t queue =dispatch_queue_create("concurrent",DISPATCH_QUEUE_SERIAL);
/ / synchronize
dispatch_sync(queue, ^{
sleep(1);
NSLog(@"Serial synchronization task------%@", [NSThread currentThread]);
});
/ / asynchronous
dispatch_async(queue, ^{
sleep(1);
NSLog(@"Serial asynchronous task------%@", [NSThread currentThread]);
});
// Concurrent queue
dispatch_queue_t queue2 =dispatch_queue_create("concurrent",DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue2, ^{
sleep(1);
NSLog(@"Concurrent task synchronization ------%@", [NSThread currentThread]);
});
dispatch_async(queue2, ^{
sleep(1);
NSLog(@"Concurrent asynchronous task------%@", [NSThread currentThread]);
});
Copy the code
Output:
Serial synchronization task------<NSThread: 0x604000060a80>{number = 1, name = main} Concurrent synchronization task------<NSThread: 0x604000060a80>{number = 1, name = main} Serial asynchronous task------<NSThread: 0x604000275E80 >{number = 3, name = (null)} Concurrent Asynchronous task------<NSThread: 0x60400026e240>{number = 4, name = (null)}Copy the code
Sync tasks, whether serial or concurrent, will only run on the current thread, which is the main thread. Only async asynchronous tasks can create new threads.
Serial queuesEvery time
onlyA task
Be implemented. Let the taskOne by one
To perform
// Serial queue
dispatch_queue_t queue =dispatch_queue_create("concurrent",DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
sleep(5);
NSLog(@"task1------%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task2------%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task3------%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task4------%@", [NSThread currentThread]);
});
Copy the code
Output:
task1------<NSThread: 0x60400007c8c0>{number = 3, name = (null)}
task2------<NSThread: 0x60400007c8c0>{number = 3, name = (null)}
task3------<NSThread: 0x60400007c8c0>{number = 3, name = (null)}
task4------<NSThread: 0x60400007c8c0>{number = 3, name = (null)}
Copy the code
Analysis: Serial queues are executed one by one in order of addition. Even asynchronous tasks wait for the previous task to complete. In the example, Task1 sleeps for 5 seconds before executing, but Task2 must wait until task1 completes. This is why there is no difference between synchronous and asynchronous tasks in a serial queue.
Parallel queues allow multiple tasks to execute simultaneously
// Concurrent queue
dispatch_queue_t queue =dispatch_queue_create("concurrent",DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
sleep(5);
NSLog(@"task1------%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task2------%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task3------%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task4------%@", [NSThread currentThread]);
});
Copy the code
Output:
task1------<NSThread: 0x60400007f740>{number = 1, name = main}
task2------<NSThread: 0x604000278240>{number = 3, name = (null)}
task4------<NSThread: 0x60000027eb80>{number = 5, name = (null)}
task3------<NSThread: 0x604000274380>{number = 4, name = (null)}
Copy the code
Task2, Task3, and Task4 are executed in unordered order. The order of execution depends on the complexity of the tasks and the CPU scheduling. Task1 is a synchronization task, and synchronization blocks the execution of the current thread, so Task1 blocks the execution of subsequent code, so task1 executes first.
2.2 Main queue and Global Queue
The home side column
The main queue is a serial queue. UI functions are executed in the main queue, dispatch_get_main_queueGlobal queue
“Dispatch_get_global_queue” is a global concurrent queue.
Above we said asynchrony starts new threads, but asynchrony does not start new threads in the main queue
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"2 - % @",[NSThread currentThread]);
});
Copy the code
Output:
2--<NSThread: 0x60400007f580>{number = 1, name = main}
Copy the code
The main thread deadlock problem is we often encounter in multi-threaded development, the following several examples to analyze why will cause deadlock?
Main thread deadlock
NSLog(@"0");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"1");
});
NSLog(@"2");
Copy the code
Sync is synchronized, so the execution of 2 will be blocked. The main queue is a serial queue, and serial queues are executed one by one, so 1 will wait for the execution of the methods added to the main queue to complete. 2 will wait for the execution of 1, and 1 will wait for the execution of the main queue to complete.
Serial queue deadlocks
dispatch_queue_t queue = dispatch_queue_create("test", NULL);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
Copy the code
Analysis: Dispatch_async (dispatch_async, dispatch_sync, dispatch_sync) (dispatch_sync, dispatch_sync) (dispatch_sync, dispatch_sync) (dispatch_sync, dispatch_sync) (dispatch_sync, dispatch_sync) (dispatch_sync, dispatch_sync) (dispatch_sync, dispatch_sync) (dispatch_sync, dispatch_sync) (dispatch_sync, dispatch_sync, dispatch_sync) Therefore, 3 waits for the dispatch_async method body to complete, causing a deadlock. One other thing to note here is that we said that serial queues are executed in the same order of addition as asynchronous queues, so why is 5 executed before 2? 5 is in the main queue, not in the test queue.
So what if you replace the serial queue with a concurrent queue?
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
Copy the code
Output:
1
5
2
3
4
Copy the code
2, synchronous code block will block the thread, 4 waits for the execution of 3, because the execution of the concurrent queue is not sequential, so 3 does not need to wait for the completion of the dispatch_async method body.
2.3 Fence function
The “dispatch_barrier_sync” and “dispatch_barrier_async” functions cause the application to execute the “barrier_sync” function, then the “barrier_async” function, then the “barrier_async” function. Here are two examples of the differences between sync and async fence functions
dispatch_barrier_async
dispatch_async(queue1, ^{
NSLog(@"1");
});
dispatch_async(queue1, ^{
NSLog(@"2");
});
dispatch_barrier_async(queue1, ^{
NSLog(@"3");
});
NSLog(@"4");
dispatch_async(queue1, ^{
NSLog(@"5");
});
dispatch_async(queue1, ^{
NSLog(@"6");
});
Copy the code
Output:
1
4
2
3
5
6
Copy the code
Dispatch_barrier_async (dispatch_barrier_async) dispatch_barrier_async (dispatch_barrier_async) dispatch_barrier_async (dispatch_barrier_async) dispatch_barrier_async (dispatch_barrier_async)
dispatch_barrier_sync
dispatch_async(queue1, ^{
NSLog(@"1");
});
dispatch_async(queue1, ^{
NSLog(@"2");
});
dispatch_barrier_sync(queue1, ^{
NSLog(@"3");
});
NSLog(@"4");
dispatch_async(queue1, ^{
NSLog(@"5");
});
dispatch_async(queue1, ^{
NSLog(@"6");
});
Copy the code
Output:
2
1
3
4
6
5
Copy the code
Dispatch_barrier_sync (dispatch_barrier_sync, dispatch_barrier_sync, dispatch_barrier_sync, dispatch_barrier_sync, dispatch_barrier_sync, dispatch_barrier_sync)
Conclusion:
Synchronize the main queue
Methods can lead toA deadlock
- Synchronized methods block thread execution
Barrier function
Must beCustomize concurrent queues
. If I use thetaSerial queues
Or provided by the systemGlobal concurrent queue
, the function of the fence function, etcSame as a synchronization function
.
3.0 Add a few concepts
3.1 Execution factors of tasks
- The CPU scheduler
- The complexity of performing tasks
- Task priority
- Thread state
3.2 Priority inversion
Two types of threads: IO intensive and CPU intensive
- IO intensive, frequently waiting threads. It’s easier to get prioritized.
- CPU intensive, rarely wait threads.
- IO – intensive threads starve to death.
- CPU scheduling to increase the priority of waiting threads
3.3 Influencing factors of priority
- User specified.
- The frequency of waiting.
- Not executing for a long time.