Welcome to the iOS Exploration series.
- IOS explores the alloc process
- IOS explores memory alignment &malloc source code
- IOS explores ISA initialization & pointing analysis
- IOS exploration class structure analysis
- IOS explores cache_T analysis
- IOS explores the nature of methods and the method finding process
- IOS explores dynamic method resolution and message forwarding mechanisms
- IOS explores the dyLD loading process briefly
- The loading process of iOS explore classes
- IOS explores the loading process of classification and class extension
- IOS explores isa interview question analysis
- IOS Explore Runtime interview question analysis
- IOS explores KVC principles and customization
- IOS explores KVO principles and customizations
- IOS explores the principle of multithreading
- IOS explores multi-threaded GCD applications
- IOS explores multithreaded GCD underlying analysis
- IOS explores NSOperation for multithreading
- IOS explores multi-threaded interview question analysis
- IOS Explore the locks in iOS
- IOS explores the full range of blocks to read
Writing in the front
Grand Central Dispatch, GCD, is pure C and offers a lot of powerful functions
Advantages of THE COMMUNIST Party of China
- GCD is apple’s solution to multi-core parallel computing
- – GCDS automatically utilize more CPU cores (such as dual core, quad core)
- GCD automatically manages thread lifecycles (thread creation, task scheduling, thread destruction)
- The programmer only needs to tell the COMMUNIST party what task it wants to perform, without writing any thread management code
Here’s what we’ll focus on: the core of GCD — adding tasks to queues and specifying the functions that execute them
A, dispatch_block_t
dispatch_block_t block = ^{
NSLog(@" Basic Use of GCD");
};
dispatch_queue_t queue = dispatch_queue_create("com.Felix".NULL);
dispatch_async(queue, block);
Copy the code
This line of code best captures the core of GCD:
dispatch_block_t
Use blocks to encapsulate tasksdispatch_queue_t
Create a queuedispatch_async
Adds the task to the queue
The above code is often written in this form
dispatch_queue_t queue = dispatch_queue_create("com.Felix".NULL);
dispatch_async(queue, ^{
NSLog(@" Basic Use of GCD");
});
Copy the code
Dispatch_sync & dispatch_async
Multi-threaded execution tasks are divided into dispatch_sync synchronous execution tasks and dispatch_async asynchronous execution tasks:
dispatch_sync
Synchronous execution- You must wait for the current statement to complete before executing the next statement
- Thread will not be opened
- Performs the task of the block in the current thread
dispatch_async
Asynchronous execution- The next statement can be executed without waiting for the current statement to complete
- Opens the thread to execute the block task
- Asynchrony is a byword for multithreading
Third, dispatch_queue_t
Serial queues
And Serial Dispatch Queue)
Concurrent Dispatch Queue
Serial queues
: Thread execution can only be executed one by one and wait for the previous execution to finish before executing the next one- use
dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL)
Creating a serial queue - You can also use
dispatch_queue_create("xxx", NULL)
Creating a serial queue (covered at the bottom of GCD)
- use
The home side column
: Binds to the main thread, a specially processed serial queue in which all tasks are executed- use
dispatch_get_main_queue()
Gets the main queue
- use
Concurrent queue
: Threads can execute together at the same time, without waiting for the previous one to complete before executing the next task- use
dispatch_queue_create("xxx", DISPATCH_QUEUE_CONCURRENT);
Creating concurrent queues
- use
Global queue
: Indicates the concurrent queue provided by the system- The easiest is to use
dispatch_get_global_queue(0, 0)
Gets the system-provided concurrent queue - The first parameter is the priority enumeration value, which defaults to
DISPATCH_QUEUE_PRIORITY_DEFAULT
= 0 - The priorities are in descending order
DISPATCH_QUEUE_PRIORITY_HIGH
,DISPATCH_QUEUE_PRIORITY_DEFAULT
,DISPATCH_QUEUE_PRIORITY_LOW
,DISPATCH_QUEUE_PRIORITY_BACKGROUND
- The easiest is to use
Serial/concurrent and synchronous/asynchronous permutations
The main queue and the global queue are considered separately, and the combined results are subject to the summary table
1. Serial + Synchronization
Tasks are executed one after another without opening up a thread
- (void)test {
NSLog(@" main thread -%@"[NSThread currentThread]);
dispatch_queue_t queue = dispatch_queue_create("Felix", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@" Serial & synchronous thread %d-%@", i, [NSThreadcurrentThread]); }); }} -------------------- The command output is -------------------
{number = 1, name = main}
0x600003B64fc0 >{number = 1, name = main}
{number = 1, name = main}
/ /... Sequential output-------------------- The command output is -------------------Copy the code
2. Serial + asynchronous
Tasks are executed one after another, opening up threads
- (void)test {
NSLog(@" main thread -%@"[NSThread currentThread]);
dispatch_queue_t queue = dispatch_queue_create("Felix", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@" Serial & asynchronous thread %d-%@", i, [NSThreadcurrentThread]); }); }} -------------------- The command output is -------------------
{number = 1, name = main}
0x6000009B8880 >{number = 6, name = (null)}
{number = 6, name = (null)}
/ /... Sequential output-------------------- The command output is -------------------Copy the code
3. Concurrency + synchronization
Tasks are executed one after another without opening up a thread
- (void)test {
NSLog(@" main thread -%@"[NSThread currentThread]);
dispatch_queue_t queue = dispatch_queue_create("Felix", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@" Concurrent & synchronous thread %d-%@", i, [NSThreadcurrentThread]); }); }} -------------------- The command output is -------------------
{number = 1, name = main}
0x600003B64fc0 >{number = 1, name = main}
{number = 1, name = main}
/ /... Sequential output-------------------- The command output is -------------------Copy the code
4. Concurrent + asynchronous
Task out of order, open up thread
- (void)test {
NSLog(@" main thread -%@"[NSThread currentThread]);
dispatch_queue_t queue = dispatch_queue_create("Felix", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@" Concurrent & asynchronous thread %d-%@", i, [NSThreadcurrentThread]); }); }} -------------------- The command output is -------------------
{number = 1, name = main}
NSThread: 0x600002A9CA40 >{number = 5, name = (null)}
NSThread: 0x600002ADD3C0 >{number = 4, name = (null)}
/ /... Out-of-order output-------------------- The command output is -------------------Copy the code
Let’s take a look at the use of primary and global queues:
5. Main queue + synchronization
Waiting for each other, causing a deadlock
- (void)test {
NSLog(@" main thread -%@"[NSThread currentThread]);
dispatch_queue_t queue = dispatch_get_main_queue();
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@" Main queue & synchronous thread %d-%@", i, [NSThreadcurrentThread]); }); }} -------------------- The command output is -------------------
{number = 1, name = main}
/ / collapse...-------------------- The command output is -------------------Copy the code
6. Main queue + asynchronous
Tasks are executed one after another without opening up a thread
- (void)test {
NSLog(@" main thread -%@"[NSThread currentThread]);
dispatch_queue_t queue = dispatch_get_main_queue();
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@" Main queue & asynchronous thread %d-%@", i, [NSThreadcurrentThread]); }); }} -------------------- The command output is -------------------
{number = 1, name = main}
NSThread: 0x600001980d40>{number = 1, name = main}
{number = 1, name = main}
/ /... Sequential output-------------------- The command output is -------------------Copy the code
7. Global queue + synchronization
Tasks are executed one after another without opening up threads (concurrent + synchronous)
- (void)test {
NSLog(@" main thread -%@"[NSThread currentThread]);
dispatch_queue_t queue = dispatch_get_global_queue(0.0);
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@" Global queue & synchronous thread %d-%@", i, [NSThreadcurrentThread]); }); }} -------------------- The command output is -------------------
{number = 1, name = main}
NSThread: 0x60000099C080 >{number = 1, name = main}
{number = 1, name = main}
/ /... Sequential output-------------------- The command output is -------------------Copy the code
8. Global queue + asynchronous
Task out of order, open up thread (concurrent + asynchronous)
- (void)test {
NSLog(@" main thread -%@"[NSThread currentThread]);
dispatch_queue_t queue = dispatch_get_global_queue(0.0);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@" Global queue & asynchronous thread %d-%@", i, [NSThreadcurrentThread]); }); }} -------------------- The command output is -------------------
{number = 1, name = main}
NSThread: 0x600001C8eb00 >{number = 3, name = (null)}
NSThread: 0x600001C82B80 >{number = 7, name = (null)}
/ /... Out-of-order output-------------------- The command output is -------------------Copy the code
To sum up:
Executionqueue | Serial queues | Concurrent queue | The home side column | Global queue |
---|---|---|---|---|
Synchronous execution | Execute sequentially without opening up threads | Execute sequentially without opening up threads | A deadlock | Execute sequentially without opening up threads |
Asynchronous execution | Execute sequentially to open up threads | Out of order execution, open up threads | Execute sequentially without opening up threads | Out of order execution, open up threads |
Four, dispatch_after
Dispatch_after Delays the execution of blocks in a queue
Application scenario: Delay execution of a task on the main queue, such as viewDidload after 1s, prompting an AlertView (delay join queue, not delay execution)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@" Output in 2 seconds");
});
Copy the code
Fifth, dispatch_once
Dispatch_once ensures that the code in the block is executed only once during the running of the App
Application scenarios: singleton and method-Swizzling
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Create singletons, Method swizzled, or other tasks
});
Copy the code
Six, dispatch_apply
Dispatch_apply appends the specified Block to the specified queue for repeated execution and waits until all processing completes — equivalent to a thread-safe for loop
Application scenario: It is used to calculate the size of each control in advance after pulling network data, preventing calculation during drawing and improving the smoothness of form sliding
- Add to serial queue — execute sequentially
- Add to main queue – deadlock
- Add to concurrent queue – out of order
- Add to global queue – out of order
- (void)test {
/** param1: indicates the number of repetitions. Param2: indicates the queue to be appended. Param3: Indicates the task to be executed
dispatch_queue_t queue = dispatch_queue_create("Felix", DISPATCH_QUEUE_SERIAL);
NSLog(@ "dispatch_apply before");
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"dispatch_apply thread %zu-%@", index, [NSThread currentThread]);
});
NSLog(After the @ "dispatch_apply"); } -------------------- The command output is -------------------/ / dispatch_apply before
0x6000019F8D40 >{number = 1, name = main}
/ /... Whether the output is in order depends on serial or concurrent queues
/ / after dispatch_apply-------------------- The command output is -------------------Copy the code
Seven, dispatch_group_t
Dispatch_group_t: scheduling group task execution group, can listening task group, and set up the waiting time
Application scenario: Refresh the page after multiple interface requests
1.dispatch_group_async
Dispatch_group_notify Notification is sent after dispatch_group_async execution is complete
- (void)test {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0.0);
dispatch_group_async(group, queue, ^{
NSLog(@" Request completed");
});
dispatch_group_async(group, queue, ^{
NSLog(@" Request 2 completed");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@" Refresh page"); }); } -------------------- The command output is -------------------// Request two completed
// Request completed
// Refresh the page-------------------- The command output is -------------------Copy the code
2.dispatch_group_enter & dispatch_group_leave
“Dispatch_group_enter” and “dispatch_group_leave” are deployed in pairs, making the logic of sending and receiving dispatch_group_leave clearer
- (void)test {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0.0);
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@" Request completed");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@" Request 2 completed");
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@" Refresh page"); }); } -------------------- The command output is -------------------// Request two completed
// Request completed
// Refresh the page-------------------- The command output is -------------------Copy the code
Scheduling group to pay attention to the use of collocation, must be advanced group and then out of the group, one cannot be absent
3.dispatch_group_wait
use
long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout)
- Group: scheduling group to be waited
- Timeout: The timeout period of waiting (i.e. how long to wait)
- Set to
DISPATCH_TIME_NOW
It indicates that the execution of the scheduling group is complete without waiting - Set to
DISPATCH_TIME_FOREVER
The current scheduling group is blocked until the scheduling group is complete
- Set to
- Return value: yes
long
type- The return value is 0 — the scheduling group completed its task within the specified time
- The return value is not 0 — the scheduling group did not complete the task on time within the specified time
Rewrite the above scheduling group code
- (void)test {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"Request completed.");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"Request two completed.");
dispatch_group_leave(group);
});
long timeout = dispatch_group_wait(group, DISPATCH_TIME_NOW);
// long timeout = dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// long timeout = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC));
NSLog(@"timeout=%ld", timeout);
if (timeout == 0) {
NSLog(@"Get things done on time");
} else {
NSLog(@"Timeout");
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Refresh page"); }); } -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the output: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / timeout = 49 / / request a complete / / request / / / / overtime refresh the page -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the output: -------------------Copy the code
Dispatch_barrier_sync & dispatch_barrier_async
Application scenario: Synchronization lock
Execute asynchronous queues concurrently
Task 3
Task 4
Task 4
GCD provides two apis — dispatch_barrier_sync and dispatch_barrier_Async — to group multiple tasks — and then append tasks to the queue after they have finished executing. In short, it is to perform the pre-fence task, then the fence task, and finally the post-fence task
1. Serial queues use the fence function
- (void)test {
dispatch_queue_t queue = dispatch_queue_create("Felix", DISPATCH_QUEUE_SERIAL);
NSLog(- % @ "@"[NSThread currentThread]);
dispatch_async(queue, ^{
sleep(2);
NSLog(@" Delay task for 2s 1 -- %@"[NSThread currentThread]);
});
NSLog(@" First end -- %@"[NSThread currentThread]);
// dispatch_barrier_async(queue, ^{
/ / NSLog (@ "-- -- -- -- -- -- -- -- -- -- the fence task -- -- -- -- -- -- -- -- -- - % @", [NSThread currentThread]);
/ /});
// NSLog(@" end -- %@", [NSThread currentThread]);
dispatch_async(queue, ^{
sleep(1);
NSLog(@" Delay task 2 -- %@ for 1s"[NSThread currentThread]);
});
NSLog(@" End of second time -- %@"[NSThread currentThread]);
}
Copy the code
Do not use the fence function
Start -- <NSThread: 0x600001068900>{number = 1, name = main} 0x600001068900>{number = 1, name = main} 0x600001068900>{number = 1, name = main} Delay task 1 -- <NSThread: 0x600001025EC0 >{number = 3, name = (null)} Delay task 2 for 1s -- <NSThread: 0x600001025EC0 >{number = 3, name = (null)}Copy the code
Using the fence function
Start -- <NSThread: 0x6000001bcf00>{number = 1, name = main} 0x6000001bcf00>{number = 1, name = main} NSThread: 0x6000001bcf00>{number = 1, name = main} 0x6000001Bcf00 >{number = 1, name = main} Delay task 1 -- <NSThread: 0 x6000001fcf00 > {number = 5, name = (null)} -- -- -- -- -- -- -- -- -- -- the fence task -- -- -- -- -- -- -- -- -- -- < NSThread: 0x6000001Bcf00 >{number = 1, name = main} Task 2 delayed for 1s -- <NSThread: 0x6000001FCF00 >{number = 5, name = (null)}Copy the code
The fence function is used to group tasks in a queue, so we just focus on task 1 and task 2
Conclusion: Due toSerial queues execute asynchronously
Tasks are executed one after another, so there is no point in using the fence function
2. Use the fence function for concurrent queues
- (void)test {
dispatch_queue_t queue = dispatch_queue_create("Felix", DISPATCH_QUEUE_CONCURRENT);
NSLog(- % @ "@"[NSThread currentThread]);
dispatch_async(queue, ^{
sleep(2);
NSLog(@" Delay task for 2s 1 -- %@"[NSThread currentThread]);
});
NSLog(@" First end -- %@"[NSThread currentThread]);
// dispatch_barrier_async(queue, ^{
/ / NSLog (@ "-- -- -- -- -- -- -- -- -- -- the fence task -- -- -- -- -- -- -- -- -- - % @", [NSThread currentThread]);
/ /});
// NSLog(@" end -- %@", [NSThread currentThread]);
dispatch_async(queue, ^{
sleep(1);
NSLog(@" Delay task 2 -- %@ for 1s"[NSThread currentThread]);
});
NSLog(@" End of second time -- %@"[NSThread currentThread]);
}
Copy the code
Do not use the fence function
Start -- <NSThread: 0x600002384F00 >{number = 1, name = main} 0x600002384F00 >{number = 1, name = main} 0x600002384F00 >{number = 1, name = main} Delay task 2 for 1s -- <NSThread: 0x6000023EC300 >{number = 5, name = (null)} Delay 2s task 1 -- <NSThread: 0x60000238C180 >{number = 7, name = (null)}Copy the code
Using the fence function
Start -- <NSThread: 0x600000820bc0>{number = 1, name = main} <NSThread: 0x600000820bc0>{number = 1, name = main} 0x600000820BC0 >{number = 1, name = main} Delay task 1 -- <NSThread: 0 x600000863c80 > {number = 4, name = (null)} -- -- -- -- -- -- -- -- -- -- the fence task -- -- -- -- -- -- -- -- -- -- < NSThread: 0x600000863C80 >{number = 4, name = (null)} Delay task 2 for 1s -- <NSThread: 0x600000863C80 >{number = 4, name = (null)}Copy the code
Conclusion: Due toConcurrent queues execute asynchronously
Tasks are executed out of order, so the fence function can be used to control the order of tasks in the queue
3. Dispatch_barrier_sync/dispatch_barrier_async difference
dispatch_barrier_async
: Will come here after the previous mission is completeddispatch_barrier_sync
: has the same effect, but this will block the thread, affecting the execution of later tasks
Change dispatch_barrier_async to dispatch_barrier_sync in case 2
Start -- <NSThread: 0x600001040D40 >{number = 1, name = main} 0x600001040D40 >{number = 1, name = main} Delay task 1 -- <NSThread: 0 x60000100ce40 > {number = 6, name = (null)} -- -- -- -- -- -- -- -- -- -- the fence task -- -- -- -- -- -- -- -- -- -- < NSThread: 0x600001040D40 >{number = 1, name = main} NSThread: <NSThread: 0x600001040D40 >{number = 1, name = main} 0x600001040D40 >{number = 1, name = main} Task 2 delayed for 1s -- <NSThread: 0x60000100CE40 >{number = 6, name = (null)}Copy the code
Conclusion: Dispatch_barrier_async can control the order in which tasks are executed in queues. Dispatch_barrier_sync blocks not only queue execution but also thread execution (use sparsely).
4. Pay attention to fence function
Use custom concurrent queues whenever possible
:- use
Global queue
Don’tBarrier function
The role of - use
Global queue
When the global queue is blocked, other parts of the system that call the global queue may also be blocked and crash (you are not the only one using this queue).
- use
The fence function can only control the same concurrent queue
For example, when MAKING network requests using AFNetworking, why can’t we use the fence function to block the synchronization because AFNetworking has its own queue
Nine, dispatch_semaphore_t
Application scenario: Control the maximum number of concurrent GCD users when synchronization is locked
dispatch_semaphore_create()
: Creates a semaphoredispatch_semaphore_wait()
: Wait for semaphore, semaphore minus 1. When a semaphore< 0
Will block the current thread, depending on the incoming wait time to decide what to do next — ifPermanent waitWill wait untilSignal
To carry it outdispatch_semaphore_signal()
: Releases the semaphore, and the semaphore increases by 1. When a semaphore> = 0
The code after WAIT is executed
The following code requires the semaphore to be output in order (of course the fence function will do the job)
- (void)test {
dispatch_queue_t queue = dispatch_queue_create("Felix", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@" Current %d---- thread %@", i, [NSThread currentThread]);
});
// Use the fence function
// dispatch_barrier_async(queue, ^{});}}Copy the code
Use the semaphore API for code rewriting
- (void)test {
// Create semaphore
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_queue_create("Felix", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@" Current %d---- thread %@", i, [NSThread currentThread]);
// The semaphore is unlocked after the printing task is complete
dispatch_semaphore_signal(sem);
});
// Because of asynchronous execution, the printing task will be slow, so the semaphore is lockeddispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); }}Copy the code
The output
Current 0---- thread <NSThread: 0x600000C2C000 >{number = 5, name = (null)} Current 1---- thread <NSThread: 0x600000C2C000 >{number = 5, name = (null)} Current 2---- threads <NSThread: 0x600000C2C000 >{number = 5, name = (null)} Current 3---- threads <NSThread: 0x600000C2C000 >{number = 5, name = (null)} Current 4---- threads <NSThread: 0x600000C2C000 >{number = 5, name = (null)} Current 5---- threads <NSThread: 0x600000C2C000 >{number = 5, name = (null)} Current 6---- threads <NSThread: 0x600000C2C000 >{number = 5, name = (null)} Current 7---- threads <NSThread: 0x600000C2C000 >{number = 5, name = (null)} Current 8---- thread <NSThread: 0x600000C2C000 >{number = 5, name = (null)} Current 9---- threads <NSThread: 0x600000C2C000 >{number = 5, name = (null)}Copy the code
What if a value of 1 was passed in when the semaphore was created?
i=0
Sometimes beforeprint
Or it may be sent firstwait
Semaphore -1, butwait
Then a semaphore of zero does not block the thread, so enteri=1
i=1
Sometimes beforeprint
Or it may be sent firstwait
Semaphore -1, butwait
Then a semaphore of -1 blocks the thread and waitssignal
Carry on
Current 1---- thread <NSThread: 0x600001448D40 >{number = 3, name = (null)} Current 0---- thread <NSThread: 0x60000140C240 >{Number = 6, name = (null)} Current 2---- threads <NSThread: 0x600001448D40 >{number = 3, name = (null)} Current 3---- threads <NSThread: 0x60000140C240 >{Number = 6, Name = (null)} Current 4---- threads <NSThread: 0x60000140C240 >{Number = 6, name = (null)} Current 5---- threads <NSThread: 0x600001448D40 >{number = 3, name = (null)} Current 6---- threads <NSThread: 0x600001448D40 >{number = 3, name = (null)} Current 7---- threads <NSThread: 0x60000140C240 >{Number = 6, Name = (null)} Current 8---- thread <NSThread: 0x600001448D40 >{number = 3, name = (null)} Current 9---- Threads <NSThread: 0x60000140C240 >{number = 6, name = (null)}Copy the code
Conclusion:
- Creating a semaphore with an incoming value of 1 can pass twice before blocking
- When the incoming value is 2, it can pass three times before blocking
Ten, dispatch_source
Application scenario: GCDTimer
1. Definition and use
Dispatch_source is a basic data type that can be used to listen for low-level system events
Timer Dispatch Source
: Timer event source that generates periodic notifications or callbacksSignal Dispatch Source
: Listens for signal event sources to notify when a UNIX signal occursDescriptor Dispatch Source
: listens for file or socket event sources and notifies them when file or socket data changesProcess Dispatch Source
: Listens for process event sources, notifications of process-related eventsMach port Dispatch Source
: Listens for Mach port event sourcesCustom Dispatch Source
: Listens for custom event sources
Main APIS used:
dispatch_source_create
: Creates an event sourcedispatch_source_set_event_handler
: Sets the data source callbackdispatch_source_merge_data
: Sets the event source datadispatch_source_get_data
: Obtains the event source datadispatch_resume
: continue todispatch_suspend
: hangdispatch_cancle
Cancelled:
2. Customize the timer
NSTimer is commonly used in iOS development to handle timing logic, but NSTimer relies on Runloop, which can run in different modes. If NSTimer is added in one mode, the timer hangs up while Runloop is running in another mode; If Runloop is blocked, NSTimer firing is delayed until the next Runloop cycle. As a result, NSTimer has errors in timing and is not particularly accurate, whereas GCD timers do not rely on Runloop and are much more accurate
@property (nonatomic.strong) dispatch_source_t timer;
1. Create a queue
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/ / 2. To create a timer
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0.0, queue);
//3. Set the first execution time, interval and accuracy of timer
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC.0.1 * NSEC_PER_SEC);
//4. Set the timer event callback
dispatch_source_set_event_handler(_timer, ^{
NSLog(@"GCDTimer");
});
//5. The state is suspended by default and needs to be activated manually
dispatch_resume(_timer);
Copy the code
Use dispatch_source to customize timers.
GCDTimer
Need to beStrong hold
Otherwise, it is released immediately out of scope and there is no event callbackGCDTimer
It is suspended by default and needs to be activated manuallyGCDTimer
There is norepeat
Encapsulation is required to increase flag bit controlGCDTimer
If a circular reference exists, useweak+strong
Or call ahead of timedispatch_source_cancel
Cancel the timerdispatch_resume
anddispatch_suspend
The number of calls needs to be balancedsource
inPending state
If you want to directly setsource = nil
Or recreate itsource
Can cause crashes. The right way is inactive
Cut withdispatch_source_cancel(source)
Release currentsource
The GCD – API
API | instructions |
---|---|
dispatch_sync() | Synchronous execution |
dispatch_async() | Asynchronous execution |
dispatch_queue_create() | Create a queue |
dispatch_get_main_queue() | Gets the main queue |
dispatch_get_global_queue() | Get global queue |
dispatch_after() | Delay to perform |
dispatch_once() | One-time execution |
dispatch_apply() | Submitted to the queue |
dispatch_group_create() | Creating a Scheduling Group |
dispatch_group_async() | Execute the group task |
dispatch_group_enter()/ dispatch_group_leave() |
Add or subtract 1 from the number of unfinished tasks in the scheduling group (The two functions should be used together) |
dispatch_group_wait() | Set the wait time (success to 0) |
dispatch_barrier_sync() | Synchronous fence function |
dispatch_barrier_async() | Asynchronous fence function |
dispatch_group_notify() | Listen queue group completes execution |
dispatch_semaphore_creat() | Create semaphore |
dispatch_semaphore_wait() | Waiting semaphore |
dispatch_semaphore_signal() | Release semaphore |
dispatch_source_create | Create the source |
dispatch_source_set_event_handler | Set the source event callback |
dispatch_source_merge_data | Source event sets data |
dispatch_source_get_data | Get the source event data |
dispatch_resume | Continue to |
dispatch_suspend | hang |
dispatch_cancle | cancel |
Write in the back
The next article will explore the underlying principles of GCD, and some of the pitfalls of GCD applications will be supplemented in multi-threaded interview questions