preface
The previous article covered the basic analysis steps of synchronization and asynchrony. Today we will talk about the practical application of GCD functions and principles, mainly: fence functions, semaphores, thread groups and Dispatch_source
Barrier function
- The fence function has a more direct effect:
Controls the order in which tasks are executed, resulting in synchronization
. - There are two types of fence functions:
dispatch_barrier_async
dispatch_barrier_sync
The following cases are used to analyze their functions:
dispatch_barrier_async
Let’s take a look at the asynchronous fence example:
- (void)testAsync_barrier {
dispatch_queue_t concurrent = dispatch_queue_create("wushuang.concurrent", DISPATCH_QUEUE_CONCURRENT);
NSLog("Here we go!");
dispatch_async(concurrent, ^{
sleep(1);
NSLog(@ "1");
});
dispatch_async(concurrent, ^{
sleep(1);
NSLog(@ "2");
});
dispatch_barrier_async(concurrent, ^{
NSLog(@"——————— Dailan ———————");
});
dispatch_async(concurrent, ^{
NSLog(@ "3");
});
dispatch_async(concurrent, ^{
NSLog(@ "4");
});
NSLog(@" ~ ~ come here ~ ~");
}
Copy the code
- For more direct observation, the asynchronous function in front of the fence has been added
sleep
, the print result is as follows:
- As you can see from the print, the fence function blocks tasks in the same thread and does not block the thread
dispatch_barrier_sync
Take a look at sync fences:
- (void)testSync_barrier {
dispatch_queue_t concurrent = dispatch_queue_create("wushuang.concurrent", DISPATCH_QUEUE_CONCURRENT);
NSLog("Here we go!");
dispatch_async(concurrent, ^{
sleep(1);
NSLog(@ "1");
});
dispatch_async(concurrent, ^{
sleep(1);
NSLog(@ "2");
});
dispatch_barrier_sync(concurrent, ^{
NSLog(@"——————— Sync Dailarun ———————");
});
dispatch_async(concurrent, ^{
NSLog(@ "3");
});
dispatch_async(concurrent, ^{
NSLog(@ "4");
});
NSLog(@" ~ ~ come here ~ ~");
}
Copy the code
First look at the print result:
- As you can see from the results, the synchronization fence function also blocks tasks in the same queue, but blocks the thread
Global queue fence
The barrier function is used to create concurrent queues. How about global queues?
- (void)testGlobalBarrier {
dispatch_queue_t global = dispatch_get_global_queue(0.0);
NSLog("Here we go!");
dispatch_async(global, ^{
sleep(1);
NSLog(@ "1");
});
dispatch_async(global, ^{
sleep(1);
NSLog(@ "2");
});
dispatch_barrier_async(global, ^{
NSLog(@"——————— Dailan ———————");
});
dispatch_async(global, ^{
NSLog(@ "3");
});
dispatch_async(global, ^{
NSLog(@ "4");
});
NSLog(@" ~ ~ come here ~ ~");
}
Copy the code
- The print result is as follows:
- The result is that nothing is blocked, indicating that the global queue is special.
Question: 1. Why can the fence function control the task 2. Why does the fence function not work in global queue
- With these two questions in mind, let’s explore libdispatch-1271.120.2
The underlying source
- In order to
dispatch_barrier_sync
To analyze, search and flow will eventually enter_dispatch_barrier_sync_f_inline
methods
- Through symbol breakpoint debugging, it is found that it will eventually walk
_dispatch_sync_f_slow
Method at the same timeDC_FLAG_BARRIER
Flag it and follow up
- According to the next sign breakpoint, determine to go
_dispatch_sync_invoke_and_complete_recurse
Method, and willDC_FLAG_BARRIER
Parameters of the incoming
- Enter the
_dispatch_sync_function_invoke_inline
Methods can be found to be_dispatch_client_callout
The method, which is equal toThe fence function call
, but the core of our research is why do we control the task and find out through the sign breakpoint that the fence function will walk after it executes_dispatch_sync_complete_recurse
methods
- Then follow up
_dispatch_sync_complete_recurse
methods
static void
_dispatch_sync_complete_recurse(dispatch_queue_t dq, dispatch_queue_t stop_dq,
uintptr_t dc_flags)
{
bool barrier = (dc_flags & DC_FLAG_BARRIER);
do {
if (dq == stop_dq) return;
if (barrier) {
dx_wakeup(dq, 0, DISPATCH_WAKEUP_BARRIER_COMPLETE);
} else {
_dispatch_lane_non_barrier_complete(upcast(dq)._dl, 0);
}
dq = dq->do_targetq;
barrier = (dq->dq_width == 1);
} while (unlikely(dq->do_targetq));
}
Copy the code
- Here is a
do-while
Loop, first of alldc_flags
The incoming isDC_FLAG_BARRIER
, so(dc_flags & DC_FLAG_BARRIER)
It must have some value, so it goes in the loopdx_wakeup
, to wake up the task in the queue, and when it is done, the fence is over, and it will go_dispatch_lane_non_barrier_complete
Function, which is to continue the flow after the fence. - Look again at this point
dx_wakeup
Delta function, at this pointflag
For the incomingDISPATCH_WAKEUP_BARRIER_COMPLETE
_dispatch_lane_wakeup
- Concurrent processes
_dispatch_root_queue_wakeup
According toflag
Judgment will go_dispatch_lane_barrier_complete
Methods:
- Called when serial or fenced
_dispatch_lane_drain_barrier_waiter
Block the task untilVerify that tasks in front of the current queue are complete
It will continue the execution of subsequent tasks
_dispatch_root_queue_wakeup
void
_dispatch_root_queue_wakeup(dispatch_queue_global_t dq,
DISPATCH_UNUSED dispatch_qos_t qos, dispatch_wakeup_flags_t flags)
{
if(! (flags & DISPATCH_WAKEUP_BLOCK_WAIT)) {DISPATCH_INTERNAL_CRASH(dq->dq_priority,
"Don't try to wake up or override a root queue");
}
if (flags & DISPATCH_WAKEUP_CONSUME_2) {
return_dispatch_release_2_tailcall(dq); }}Copy the code
- What is not done in the global concurrent queue source code, where the fence is equivalent to a normal asynchronous concurrent function
Didn't work
Why? Global concurrency is a concurrent queue created by the system. Blocking can cause problems for system tasks, so you cannot use all concurrent queues when using the fence function
conclusion
-
- Fence function can block the current thread of the task, to achieve the effect of task control, but only in
The concurrent queue created
The use of
- Fence function can block the current thread of the task, to achieve the effect of task control, but only in
-
- The fence function can also be used in multi-read single-write scenarios
-
- The fence function can only be used in the current thread, if multiple threads do not have the desired effect
A semaphore
- in
The self-cultivation of programmers
The book’sOn page 26
, have toBinary semaphore
It’s only0
and1
Two states,Multivariate semaphore
Referred to as”A semaphore
GCD
Semaphore indispatch_semaphore_t
There are three main functions in:dispatch_semaphore_create
: Create signaldispatch_semaphore_wait
: Waiting for signaldispatch_semaphore_signal
: Release signal
Case analysis
- (void)testDispatchSemaphore {
dispatch_queue_t global = dispatch_get_global_queue(0.0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSLog(@" ~ ~ start ~ ~");
dispatch_async(global, ^{
NSLog(@" ~ ~ 0 ~ ~");
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@" ~ ~ 1 ~ ~");
});
dispatch_async(global, ^{
NSLog(@" ~ ~ 2 ~ ~");
sleep(2);
dispatch_semaphore_signal(semaphore);
NSLog(@" ~ ~ 3 ~ ~");
});
NSLog(@" ~ ~ come here ~ ~");
}
Copy the code
- The running results are as follows:
- As you can see from the print result, an asynchronous task was executed first, so it was printed
0
, but there was no signal, sodispatch_semaphore_wait
Just wait in place, cause1
The second asynchronous task is executed and printed2
And thendispatch_semaphore_signal
Give the signal, and then1
It’s ready to print
The source code interpretation
Take a look at source code analysis
dispatch_semaphore_create
- First of all if the signal is less than
0
, returns oneDISPATCH_BAD_INPUT
Type object, that is, return a_Nonnull
- If the signal
Greater than or equal to 0
, you will get todispatch_semaphore_t
objectdsema
Do some assignments and returndsema
object
dispatch_semaphore_wait
intptr_t
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout)
{
long value = os_atomic_dec2o(dsema, dsema_value, acquire);
if (likely(value >= 0)) {
return 0;
}
return _dispatch_semaphore_wait_slow(dsema, timeout);
}
Copy the code
- The waiting signal is mainly through
os_atomic_dec2o
functionSubtracting the signal
whenValue greater than or equal to 0
When to return to0
- The duty
Less than zero
When will go_dispatch_semaphore_wait_slow
methods
_dispatch_semaphore_wait_slow
-
When timeout is set, operations are performed according to the type. In this article DISPATCH_TIME_FOREVER is used. In this case, _dispatch_sema4_wait is called:
- Here’s mainly one
do-while
In the loop, the queue waits for the signal, and when the condition is not met, the loop will jump out, so there will be a waiting effect
- Here’s mainly one
dispatch_semaphore_signal
intptr_t
dispatch_semaphore_signal(dispatch_semaphore_t dsema)
{
long value = os_atomic_inc2o(dsema, dsema_value, release);
if (likely(value > 0)) {
return 0;
}
if (unlikely(value == LONG_MIN)) {
DISPATCH_CLIENT_CRASH(value,
"Unbalanced call to dispatch_semaphore_signal()");
}
return _dispatch_semaphore_signal_slow(dsema);
}
Copy the code
- The main way to send signals is through
os_atomic_inc2o
Carry on a signalSince the increase
, if the increment afterIt's greater than zero
, it returns0
- if
It's still less than 0
, will go to_dispatch_semaphore_signal_slow
methods
_dispatch_semaphore_signal_slow
intptr_t
_dispatch_semaphore_signal_slow(dispatch_semaphore_t dsema)
{
_dispatch_sema4_create(&dsema->dsema_sema, _DSEMA4_POLICY_FIFO);
_dispatch_sema4_signal(&dsema->dsema_sema, 1);
return 1;
}
Copy the code
- Here is a
_dispatch_sema4_signal
Function to send signals slowly
Scheduling group
- The most direct function of the scheduling group is:
Control the execution sequence of tasks
.Api
There are mainly the following methods:dispatch_group_create
: create a groupdispatch_group_async
: Group tasksdispatch_group_notify
: Indicates a notification that a group task is completeddispatch_group_enter
: into the groupdispatch_group_leave
: a group ofdispatch_group_wait
: Waiting group task time
Case analysis
dispatch_group_async
- (void)testDispatchGroup1 {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(0.0);
dispatch_group_async(group, globalQueue, ^{
sleep(1);
NSLog(@ "1");
});
NSLog(@ "2");
dispatch_group_async(group, globalQueue, ^{
sleep(1);
NSLog(@ "3");
});
NSLog(@ "4");
dispatch_group_notify(group, globalQueue, ^{
NSLog(5 "@");
});
NSLog(@" ~ ~ 6 ~ ~");
}
Copy the code
- Speaking tasks
1 and 3
Put it in the group task, and then put it5
Task indispatch_group_notify
, the following output is displayed:
- The output results can be concluded as follows:
-
Scheduling groups do not block threads
-
- Set of tasks
No order of execution
, equivalent to an asynchronous concurrent queue
- Set of tasks
-
- Group tasks are executed only after they are complete
dispatch_group_notify
task
- Group tasks are executed only after they are complete
-
dispatch_group_wait
-
- The task
1 and 3
Place them in both task groups and execute them belowdispatch_group_wait
Waiting for the10 seconds
- The task
- (void)testDispatchGroup1 {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(0.0);
dispatch_group_async(group, globalQueue, ^{
sleep(5);
NSLog(@ "1");
});
NSLog(@ "2");
dispatch_group_async(group, globalQueue, ^{
sleep(5);
NSLog(@ "3");
});
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 10);
dispatch_group_wait(group, time);
NSLog(@" ~ ~ 6 ~ ~");
}
Copy the code
- The following output is displayed:
Found waiting is10 seconds
, but5 seconds
After the task is executed, execute it immediatelyTask 6
-
- Change the waiting time to
3 seconds
:
- Change the waiting time to
Here is the etc.3 seconds
Find the group task is not finished to execute6
task
- conclusion:
dispatch_group_wait
The role of isBlocks tasks outside the scheduling group
:-
- When the waiting time ends, the group task is not completed, and the block is finished to execute other tasks
-
- When the group task is complete and the waiting time is not over, the system stops blocking and executes other tasks
-
In group + out group
- (void)testDispatchGroup2 {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(0.0);
dispatch_group_enter(group);
dispatch_async(globalQueue, ^{
sleep(1);
NSLog(@ "1");
dispatch_group_leave(group);
});
NSLog(@ "2");
dispatch_group_enter(group);
dispatch_async(globalQueue, ^{
sleep(1);
NSLog(@ "3");
dispatch_group_leave(group);
});
dispatch_group_notify(group, globalQueue, ^{
NSLog(@ "4");
});
NSLog(5 "@");
}
Copy the code
In group + out group
Is basically the same as the above case, only into the group of tasks divided intoIn group + out group
The result is as follows:
-
The output of dispatch_group_async is consistent with that of dispatch_group_async
-
In group + out group combination has several precautions, they must be in pairs, must be advanced after the group, otherwise the following problems will occur:
-
- If one is missing
dispatch_group_leave
,dispatch_group_notify
Do not perform
- If one is missing
-
- If one is missing
dispatch_group_enter
After the task is executed, the system exitsnotify
But it’s not rightdispatch_group_leave
Place will collapse
- If one is missing
-
- If the first
leave
afterenter
, will directly crash inleave
place
- If the first
-
Question: 1. How does the scheduling group achieve process control? 2. Why are dispatch_group_async and dispatch_group_async used together? 3. Why does dispatch_group_leave crash?
With the question, let’s explore the source code
The principle of analysis
dispatch_group_creat
dispatch_group_t
dispatch_group_create(void)
{
return _dispatch_group_create_with_count(0);
}
Copy the code
The dispatch_group_create method calls the _dispatch_group_create_with_count method, passing in the parameter 0
static inline dispatch_group_t
_dispatch_group_create_with_count(uint32_t n)
{
dispatch_group_t dg = _dispatch_object_alloc(DISPATCH_VTABLE(group),
sizeof(struct dispatch_group_s));
dg->do_next = DISPATCH_OBJECT_LISTLESS;
dg->do_targetq = _dispatch_get_default_queue(false);
if (n) {
os_atomic_store2o(dg, dg_bits,
(uint32_t)-n * DISPATCH_GROUP_VALUE_INTERVAL, relaxed);
os_atomic_store2o(dg, do_ref_cnt, 1, relaxed); // <rdar://22318411>
}
return dg;
}
Copy the code
- The core of the method is creation
dispatch_group_t
objectdg
And on itdo_next
anddo_targetq
Parameter is assigned and then calledos_atomic_store2o
For storage
dispatch_group_enter
void
dispatch_group_enter(dispatch_group_t dg)
{
// The value is decremented on a 32bits wide atomic so that the carry
// for the 0 -> -1 transition is not propagated to the upper 32bits.
uint32_t old_bits = os_atomic_sub_orig2o(dg, dg_bits,
DISPATCH_GROUP_VALUE_INTERVAL, acquire);
uint32_t old_value = old_bits & DISPATCH_GROUP_VALUE_MASK;
if (unlikely(old_value == 0)) {
_dispatch_retain(dg); // <rdar://problem/22318411>
}
if (unlikely(old_value == DISPATCH_GROUP_VALUE_MAX)) {
DISPATCH_CLIENT_CRASH(old_bits,
"Too many nested calls to dispatch_group_enter()"); }}Copy the code
Os_atomic_sub_orig2o is used to decrement from 0 -> -1, but does not wait for the semaphore
dispatch_group_leave
void
dispatch_group_leave(dispatch_group_t dg)
{
// The value is incremented on a 64bits wide atomic so that the carry for
// the -1 -> 0 transition increments the generation atomically.
uint64_t new_state, old_state = os_atomic_add_orig2o(dg, dg_state,
DISPATCH_GROUP_VALUE_INTERVAL, release);
uint32_t old_value = (uint32_t)(old_state & DISPATCH_GROUP_VALUE_MASK);
if (unlikely(old_value == DISPATCH_GROUP_VALUE_1)) {
old_state += DISPATCH_GROUP_VALUE_INTERVAL;
do {
new_state = old_state;
if ((old_state & DISPATCH_GROUP_VALUE_MASK) == 0) {
new_state &= ~DISPATCH_GROUP_HAS_WAITERS;
new_state &= ~DISPATCH_GROUP_HAS_NOTIFS;
} else {
// If the group was entered again since the atomic_add above,
// we can't clear the waiters bit anymore as we don't know for
// which generation the waiters are for
new_state &= ~DISPATCH_GROUP_HAS_NOTIFS;
}
if (old_state == new_state) break;
} while (unlikely(!os_atomic_cmpxchgv2o(dg, dg_state,
old_state, new_state, &old_state, relaxed)));
return _dispatch_group_wake(dg, old_state, true);
}
if (unlikely(old_value == 0)) {
DISPATCH_CLIENT_CRASH((uintptr_t)old_value,
"Unbalanced call to dispatch_group_leave()"); }}Copy the code
Run the OS_ATOMic_ADD_ORIG2O command to increment old_state from -1 to 0
DISPATCH_GROUP_VALUE_MASK 0x00000000fffffffcULL
DISPATCH_GROUP_VALUE_1 DISPATCH_GROUP_VALUE_MASK
Copy the code
-
old_value
Is equal to theold_state & DISPATCH_GROUP_VALUE_MASK
Is equal to the0
At this time,old_value ! = DISPATCH_GROUP_VALUE_1
, again due to the judgment isunlikely
So they willEnter if judgment
-
- Due to the
DISPATCH_GROUP_VALUE_INTERVAL = 4
, so at this timeold_state = 4
And then enter thedo-while
Cycle, it’s going to goelse
judgenew_state &= ~DISPATCH_GROUP_HAS_NOTIFS= 4 & ~2 = 4
, at this momentold_state
andnew_state
Equal, and then out of the loop_dispatch_group_wake
Method, that is, wake updispatch_group_notify
methods
- Due to the
-
- if
enter
Two, thenold_state=-1
, plusAfter 4
for3
, that is, atdo-while
Loop,new_state = old_state = 3
. thenNew_state &= ~DISPATCH_GROUP_HAS_NOTIFS = 3 & ~ 2 = 1
And thenRange and old_state
It’s going to loop again, when it’s going to loop againleave
After the increment operation, the new loop judgment will go to_dispatch_group_wake
Function to wake up
- if
dispatch_group_notify
static inline void
_dispatch_group_notify(dispatch_group_t dg, dispatch_queue_t dq,
dispatch_continuation_t dsn)
{
uint64_t old_state, new_state;
dispatch_continuation_t prev;
dsn->dc_data = dq;
_dispatch_retain(dq);
prev = os_mpsc_push_update_tail(os_mpsc(dg, dg_notify), dsn, do_next);
if (os_mpsc_push_was_empty(prev)) _dispatch_retain(dg);
os_mpsc_push_update_prev(os_mpsc(dg, dg_notify), prev, dsn, do_next);
if (os_mpsc_push_was_empty(prev)) {
os_atomic_rmw_loop2o(dg, dg_state, old_state, new_state, release, {
new_state = old_state | DISPATCH_GROUP_HAS_NOTIFS;
if ((uint32_t)old_state == 0) {
os_atomic_rmw_loop_give_up({
return _dispatch_group_wake(dg, new_state, false); }); }}); }}Copy the code
Os_atomic_rmw_loop2o is used to execute the do-while loop. When olD_state == 0, _dispatch_group_wake is executed
- There’s still one problem left to solve, which is
dispatch_group_async
And whyIn group + out group
The effect is the same, then analyze the source code
dispatch_group_async
void
dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
dispatch_block_t db)
{
dispatch_continuation_t dc = _dispatch_continuation_alloc();
uintptr_t dc_flags = DC_FLAG_CONSUME | DC_FLAG_GROUP_ASYNC;
dispatch_qos_t qos;
qos = _dispatch_continuation_init(dc, dq, db, 0, dc_flags);
_dispatch_continuation_group_async(dg, dq, dc, qos);
}
Copy the code
The function that is familiar, and asynchronous function much like, but at the moment dc_flags = DC_FLAG_CONSUME | DC_FLAG_GROUP_ASYNC, then entered the _dispatch_continuation_group_async function:
static inline void
_dispatch_continuation_group_async(dispatch_group_t dg, dispatch_queue_t dq,
dispatch_continuation_t dc, dispatch_qos_t qos)
{
dispatch_group_enter(dg);
dc->dc_data = dg;
_dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}
Copy the code
Here we see dispatch_group_enter, but we don’t see leave. I assume that leave must be executed where the block is executed, otherwise we can’t ensure that the task in the group is completed. The _dispatch_continuation_INVOke_inline function is found based on dq_push = _dispatch_root_queue_push of type global
For ordinary asynchronous types, the _dispatch_client_callout function is used, and for DC_FLAG_GROUP_ASYNC group type, _dispatch_continuation_WITH_group_invoke function is used
static inline void
_dispatch_continuation_with_group_invoke(dispatch_continuation_t dc)
{
struct dispatch_object_s *dou = dc->dc_data;
unsigned long type = dx_type(dou);
if (type == DISPATCH_GROUP_TYPE) {
_dispatch_client_callout(dc->dc_ctxt, dc->dc_func);
_dispatch_trace_item_complete(dc);
dispatch_group_leave((dispatch_group_t)dou);
} else {
DISPATCH_INTERNAL_CRASH(dx_type(dou), "Unexpected object type"); }}Copy the code
If the type is “DISPATCH_GROUP_TYPE”, the dispatch_client_callout command is executed first and then the “dispatch_group_leave” command is executed
Signal sourceDispatch_source
- Signal source
Dispatch_source
Is a try not to occupy resources, andCPU
Very low loadApi
, it does not sufferRunloop
The influence is the sumRunloop
A flat setApi
. It mainly consists of the following functions:-
dispatch_source_create
: Creates a signal source
-
dispatch_source_set_event_handler
: Sets the signal source callback
-
dispatch_source_merge_data
: Source time setting data
-
dispatch_source_get_data
: Obtains signal source data
-
dispatch_resume
: continue to
-
dispatch_suspend
: hang
-
- Call a function on any thread
dispatch_source_merge_data
After that, it will executeDispatch Source
Predefined handle (can be understood as ablock
), a process calledCustom event
User events, yesDispatch Source
An event that supports processing
Source type
- Create the source
dispatch_source_t dispatch_source_create(dispatch_source_type_t type, uintptr_t handle, uintptr_t mask, dispatch_queue_t _Nullable queue); Copy the code
- The first parameter is theta
dispatch_source_type_t
The type oftype
And thenhandle
andmask
Are alluintptr_t
Type, and finally pass in a queue
- The first parameter is theta
- Usage:
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0.0.dispatch_get_main_queue()); Copy the code
- The type of source
dispatch_source_type_t
:-
DISPATCH_SOURCE_TYPE_DATA_ADD
: used toADD
Merge data
-
DISPATCH_SOURCE_TYPE_DATA_OR
: used toBitwise or
Merge data
-
DISPATCH_SOURCE_TYPE_DATA_REPLACE
:tracking
By calling thedispatch_source_merge_data
The dispatch source of the obtained data, and the newly obtained data values willreplace
Not yet delivered to the source handlerExisting data values of
-
DISPATCH_SOURCE_TYPE_MACH_SEND
: Used for monitoringThe Mach port
theInvalid name
The dispatch source of notifications can only be sentNo receive permission
-
DISPATCH_SOURCE_TYPE_MACH_RECV
: used toMonitoring Mach ports
thehang
The message
-
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE
: used tomonitoring
systemMemory pressure change
-
DISPATCH_SOURCE_TYPE_PROC
: used toMonitoring external processes
In the event
-
DISPATCH_SOURCE_TYPE_READ
:monitoring
File descriptor asGets a readable pending byte
The dispatch of the source
-
DISPATCH_SOURCE_TYPE_SIGNAL
:Monitoring current Processes
To obtain the scheduling source of the signal
-
DISPATCH_SOURCE_TYPE_TIMER
Based on:Timer commit event
The dispatch source of the handler block
-
DISPATCH_SOURCE_TYPE_VNODE
: used tomonitoring
File descriptorDefined events
The dispatch of the source
-
DISPATCH_SOURCE_TYPE_WRITE
:monitoring
File descriptor asGets writable bytes
The dispatch source of the available buffer space.
-
The timer
The following uses a Dispatch Source to encapsulate a timer
- (void)testTimer {
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0.0.dispatch_get_global_queue(0.0));
dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, 0);
dispatch_source_set_timer(self.timer, startTime, 1 * NSEC_PER_SEC, 0);
__block int a = 0;
dispatch_source_set_event_handler(self.timer, ^{
a++;
NSLog(@"A value % d", a);
});
dispatch_resume(self.timer);
self.isRunning = YES;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (self.isRunning) {
dispatch_suspend(self.timer);
// dispatch_source_cancel(self.timer);
self.isRunning = NO;
NSLog(@"Halftime.");
} else {
dispatch_resume(self.timer);
self.isRunning = YES;
NSLog(@"Keep drinking."); }}Copy the code
The following output is displayed:
- Creating a Timer
dispatch_source_create
Be sure to useProperty or instance variable receive
Otherwise, the timer will not be executed dispatch_source_set_timer
The second argument tostart
Since when, the third parameterinterval
Is the time interval,leeway
It’s the nanosecond deviation of the timer- There are two kinds of timer stops:
dispatch_resume
: Timer paused but always online, can be woken updispatch_source_cancel
: Timer release, executedispatch_resume
Wake up, crash