This is the 20th day of my participation in the August More Text Challenge
review
In the last blog has made a GCD dispatch group introduction and example application, as well as the underlying source analysis, so this blog will be on the event source dispatch_source analysis!
Multithreading in iOS (I) – Processes and threads
IOS low-level exploration of multithreading (II) – Threads and locks
IOS low-level exploration of multithreading (3) – GCD
IOS low-level exploration of multithreading (4) – GCD queue
IOS bottom exploration of multithreading (five) – GCD different queue source analysis
IOS bottom exploration of multithreading (six) – GCD source analysis (sync function, async asynchronous function)
IOS low-level exploration of multithreading (seven) – GCD source analysis (cause of deadlock)
IOS bottom exploration of multithreading (eight) – GCD source analysis (function synchronization, asynchrony, singleton)
IOS bottom exploration of multithreading (9) – GCD source analysis (dispatch_barrier_sync)
Multithreading in iOS (10) — GCD source code Analysis (Dispatch Semaphore)
IOS low-level exploration of multithreading (11) – GCD source analysis (Dispatch_group)
1. Dispatch Source is introduced
The Dispatch Source is a wrapper around the BSD kernel’s customary kqueue, a technique that performs processing on the application programmer side when an event occurs in the XNU kernel.
It has a very low CPU load and uses as little resources as possible. When an event occurs, the Dispatch Source performs the processing of the event in the specified Dispatch Queue.
dispatch_source_create
: create the sourcedispatch_source_set_event_handler
: Sets the source callbackdispatch_source_merge_data
: Source event setting datadispatch_source_get_data
: Gets the source event datadispatch_resume
: Resume resumedispatch_suspend
: hang
In our daily development, we often use timer NSTimer, such as the countdown to send SMS, or the update of the progress bar. However, NSTimer needs to be added to NSRunloop and is affected by mode. It is interrupted when it is affected by other event sources. When sliding scrollView, mode will be switched and the timer will stop, resulting in inaccurate timer timing.
GCD provides a solution dispatch_source to come up with a similar requirement scenario.
- The time is more accurate.
CPU
Small load, less occupation of resources - You can use child threads to solve the UI problem of timer running on the main thread
- You can pause, you can continue, you don’t have to
NSTimer
The same needs to be created again
2. Dispatch the Source to use
The code to create the event source:
// Method declaration
dispatch_source_t dispatch_source_create(
dispatch_source_type_t type,
uintptr_t handle,
unsigned long mask,
dispatch_queue_t _Nullable queue);
// The implementation process
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0.0, dispatch_get_main_queue());
Copy the code
When creating, you pass in two important parameters:
dispatch_source_type_t
The type of source to createdispatch_queue_t
A scheduling queue for event processing
2.1 Type of Dispatch Source
- Dispatch Source type:
-
The DISPATCH_SOURCE_TYPE_DATA_ADD variable is increased
-
DISPATCH_SOURCE_TYPE_DATA_OR variables OR
-
DISPATCH_SOURCE_TYPE_DATA_REPLACE The newly obtained data value replaces the existing one
-
DISPATCH_SOURCE_TYPE_MACH_SEND MACH port send
-
DISPATCH_SOURCE_TYPE_MACH_RECV MACH port received
-
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE Memory pressure (note: available after iOS8)
-
DISPATCH_SOURCE_TYPE_PROC Detected process-related events
-
DISPATCH_SOURCE_TYPE_READ Reads file images
-
DISPATCH_SOURCE_TYPE_SIGNAL Receives signals
-
DISPATCH_SOURCE_TYPE_TIMER timer
-
The DISPATCH_SOURCE_TYPE_VNODE file system is changed
-
DISPATCH_SOURCE_TYPE_WRITE Writes file images
Example for designing a timer:
- Hit the screen to start
usedispatch_source
The timer can be paused and started without being affected by the main threadUI events
So its timing is accurate. As shown below:
2.2 Precautions for use
Matters needing attention
- Source needs to be started manually
Dispatch Source is most used to realize timer. After Source is created, it is suspended by default and dispatch_resume needs to be manually called to start the timer. Dispatch_after simply encapsulates the call to the Dispatch source timer and then executes the defined block in the callback function.
- A circular reference
Because the dispatch_source_set_event_handle callback is a block, it is copied when added to the source list and is strongly referenced by the source. If the block holds self and self holds the source, it causes a circular reference. Therefore, the correct method is to cancel the timer by using weak+strong or calling dispatch_source_cancel in advance.
- Suspend calls to maintain a balance
There is a balance between dispatch_resume and dispatch_suspend calls. If dispatch_resume is called repeatedly, it crashes because it disestablishes the if branch of the dispatch_resume code. DISPATCH_CLIENT_CRASH(” Over-resume of an object “) was executed, causing the crash.
- Source creation and release timing
Source in the suspend state, setting source = nil or recreating source will cause crash. The correct way is to restore the resume with dispatch_source_cancel(source).
3. Dispatch Source Source analysis
Then go to the underlying source code to see why there are some problems above.
3.1 dispatch_resume
- dispatch_resume
void
dispatch_resume(dispatch_object_t dou)
{
DISPATCH_OBJECT_TFB(_dispatch_objc_resume, dou);
if (unlikely(_dispatch_object_is_global(dou) ||
_dispatch_object_is_root_or_base_queue(dou))) {
return;
}
if(dx_cluster(dou._do) == _DISPATCH_QUEUE_CLUSTER) { _dispatch_lane_resume(dou._dl, DISPATCH_RESUME); }}Copy the code
Dispatch_resume will execute _dispatch_lane_resume
- _dispatch_lane_resume
The method here is to judge the related state of the event source, if excessiveresume
Recovery, it willgoto
Go to theover_resume
Flow, directly upDISPATCH_CLIENT_CRASH
To collapse.
There is also a determination of the pending count, which contains all pending and inactive bits. An underflow underflow means that an overrecovery or pause count needs to be moved to an edge count, that is, a continuous recovery is required if the current counter is not yet in a runnable state.
3.2 dispatch_suspend
- Hang dispatch_suspend
在dispatch_suspend
Can also be found in the definition of, restore and suspend must beKeep the balance
A suspended object does not call any of its associated objectsblock
. In any run associated with the objectblock
When done, the object will be suspended.
void
dispatch_suspend(dispatch_object_t dou)
{
DISPATCH_OBJECT_TFB(_dispatch_objc_suspend, dou);
if (unlikely(_dispatch_object_is_global(dou) ||
_dispatch_object_is_root_or_base_queue(dou))) {
return;
}
if (dx_cluster(dou._do) == _DISPATCH_QUEUE_CLUSTER) {
return_dispatch_lane_suspend(dou._dl); }}Copy the code
- _dispatch_lane_suspend
- _dispatch_lane_suspend_slow
Also here a pause is maintained to suspend the counter if it is called consecutivelydispatch_suspend
The unsigned underflow of the subtraction may occur because another thread may have touched the value when we tried to acquire the lock, or because another thread raced to perform the same operation and acquire the lock first.
So you can’t repeat the suspension or recovery, must be one of you one of me, you two of me two, keep a balanced.
4. To summarize
- Use timer
NSTimer
Need to joinNSRunloop
, resulting in inaccurate count, can be usedDispatch Source
To solve the Dispatch Source
Pay attention to the use ofrestore
andhang
tobalance
source
insuspend
In state, if the value is directly setsource = nil
Or recreate itsource
Can causecrash
. The right way is inresume
State call downdispatch_source_cancel(source)
Then create it again.- because
dispatch_source_set_event_handle
The callback isblock
, before adding tosource
Is executed on the linked listcopy
And wassource
Strong reference, ifblock
Hold in theself
.self
Hold againsource
This will cause circular references. So the right way is to useweak+strong
Or pretunedispatch_source_cancel
canceltimer
.
More content continues to be updated
🌹 if you like, give it a thumbs up 👍🌹
🌹 feel harvest, can come to a wave, collection + attention, comment + forward, so as not to find me next time 😁🌹
🌹 welcome everyone to leave a message exchange, criticism and correction, learn from each other 😁, improve themselves 🌹