当前位置:网站首页>Get to know handler again
Get to know handler again
2022-06-30 09:03:00 【Silent Pinocchio】
Reunderstanding Handler
This article Not to take everyone to understand Handler How it works and so on , Is mainly to introduce to you Handler Blocking principle and message barrier mechanism , Here's a hint You can read on demand .
Handler Can be said to be App The heart of the , Driving the whole App Execution of all events . Next, let's explore Handler Blocking and message leveling barriers .
Blocking mechanism
First understand what is called blocking ?
For example, we ordered a takeout , We don't have to keep asking if the rider's takeout has arrived , We can continue to do other things first , The rider will call us when he arrives . This process is blocking .
stay MessageQueue After taking out the message , Calculate by time comparison Need blocking time , If there is no time , If the blocking time is required, it is assigned as -1
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
And then through nativePollOnce To block
nativePollOnce(ptr, nextPollTimeoutMillis);
This nativePollOnce It's a native Method , Let's go on to analyze :
I won't list them here Post the calling code , The process will be called directly post
nativePollOnce
-> android_os_MessageQueue_nativePollOnce (android_os_MessageQueue.cpp)
-> NativeMeaageQueue::pollOnce
->Looper::pollOnce (Looper.cpp)
->Looper::pollInner->epoll_wait
During the call , You can see The blocking time parameter To the last epoll_wait In this function
Looper.cpp
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
That explains. , The obstruction is caused by epoll_wait Accomplished . So what is epoll ? Next , A little explanation .
Here is another concept to you :
Non blocking busy polling :
Or did we order a takeout , But we are very hungry now , We need the rider's cell phone number , Then call the rider in a minute , This is non blocking busy polling .
We ask the Internet , Read data from the database , As long as the data is processed, it will be involved I/O, Now we have more than one I/O event , So how do we deal with multiple streams ?
Multiple threads To deal with multiple IO flow , The efficiency will be particularly low , This is from CPU Determined by design , All will be handled by one thread I/O
while (true){
for ( i -> stream[]) {
if (i has data){
read data until unavailable
}
}
}
We can do things like this , Use non blocking busy polling to process multiple IO, Always traverse each stream , When you read that there is data in the stream , Will process the data , After that Then continue polling . But when there is no data in all streams ,cpu Will be idling , Waste resources in vain . You should give way to cpu resources , So there is select Mechanism .
while (true){
select(stream[])
for ( i -> stream[]) {
if (i has data){
read data until unavailable
}
}
}
from select You can know , Yes IO The incident happened , Then poll the stream , To process data . When there's no data , It's in select There is a blockage in .
although select You can know that there are IO The incident happened , But I don't know which streams , So you can only poll all streams indiscriminately . This indifference polling is obviously a waste of resources .
stay linux2.6 after , There is epoll Mechanism
Let's look at it first epoll Official explanation
epoll yes linux An extensible kernel IO event Processing mechanism , When a large number of applications , Good performance can be obtained .
while (true){
activite_stream[] = epoll_wait();
for ( i -> activity_stream[]) {
read data until unavailable
}
}
epoll Will Which streams have events to tell us , We can stream data , Each stream operated in this way has data . Direct responsibility from O(N) Down to O(1).
epoll There are only three ways to use :
int epoll_create(it size)
Create a epoll Handle ,size It is used to tell the kernel how much it needs to monitor
int epoll_ctl(int epfd,int op,int fd, struct epoll_event *event);
This is a epoll Time registration function
int epoll_wait(int epfd,struct epoll_event * event ,int maxevents,int timeout);
This is the blocking mentioned above , Parameters events The collection used to get events from the kernel ,maxevents Used to tell the kernel This events How big is the , This maxevents Value of cannot be greater than create epoll_create() At the time of the size, Parameters timeout It's a timeout event ( millisecond ,0 Will return immediately ,-1 Will be blocked all the time )
epoll The creation and registration of is in a function
void Looper::rebuildEpollLocked() {
....
mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
epoll_event wakeEvent = createEpollEvent(EPOLLIN, WAKE_EVENT_FD_SEQ);
int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &wakeEvent);
....
}
This function is in native Of Looper Called in the construction method .
Since there is a blockage , You have to wake up
MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
When I heard from the queue , You can see There is a wake-up operation here , This operation is finally called to Looper.cpp Of wake In the method
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ wake", this);
#endif
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",
mWakeEventFd.get(), nWrite, strerror(errno));
}
}
}
The way to wake up is through linux pipe Mechanism towards Monitoring fd Middle write data , Will wake up .
In general ,handler When there is no task to perform , Would pass epoll Mechanism blocking , Give up cpu resources , When sending a message to the queue , It will wake up and write data to the monitored file descriptor , Wake up the epoll , To continue processing messages .
The message barrier
That's the blocking mechanism , Let's talk about the news barrier again .
A message barrier is a barrier to unimportant messages , Prioritize important messages .
What is the important news ? for example UI The draw , Click events, etc .
handler There are three types of messages sent :
- General news
- Barrier news
- Asynchronous messaging
from MessageQueue When getting news from , You can see such a situation :
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
We all know message Of target It's used to distribute data handler , that tartget How can it be empty ? That's because target == null This means that this message is a barrier message .
Barrier news Namely Flag to start processing asynchronous messages ,handler After receiving the barrier message , Start processing asynchronous messages , General message deferred processing .
MessageQueue.java
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) {
// invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
This is sending a barrier message , It is also sorted by time , The only difference from other news is that there is no target.
This method is in ViewRootImpl In the :
void
() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// Send a barrier message
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// Execute one UI Refresh task
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
And then look at it mChoreographer The execution of the mission
Finally, it will be called here
Choreographer.java
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
.......
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
// Set message to asynchronous
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
This is sending an asynchronous message , Then look at the treatment :
MessageQueue.java -> next Method
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
.....
return msg;
}
ad locum When target == null When , That is, when the message barrier opens , Take out Asynchronous messaging , Then return , Distribution processing .
There is an opening barrier, there is a closing barrier :
private void removeCallbacksInternal(int callbackType, Object action, Object token) {
synchronized (mLock) {
mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
if (action != null && token == null) {
mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
}
}
}
Remove the barrier message , You can handle ordinary messages normally .
Let's connect , ViewRootImpl Processing UI Before the incident , Send a barrier message first , tell handler Prioritize asynchronous messages , then Choreographer Send asynchronous message (msg.setAsynchronous(true)), After asynchronous message processing , Then send a message to remove the barrier .
Handler It is through this mechanism that we UI The interface is refreshed smoothly .
summary
thus , This article will be finished , Mainly about handler Of epoll Blocking mechanism and handler Message barrier . Mainly to let everyone have a deeper understanding , Not limited to the surface execution principle .
边栏推荐
- Esp32 things (x): other functions
- Detectron2 source code reading 4-- registrar construction model
- Six implementation methods of singleton mode
- Rew acoustic test (VI): signal and measurement
- 使用华为性能管理服务,按需配置采样率
- Enhance the add / delete operation of for loop & iterator delete collection elements
- 14岁懂社会-《关于“工作的幸福”这件事儿》读书笔记
- c#获取当前的时间戳
- Talk about the kotlin cooperation process and the difference between job and supervisorjob
- Coredata acquisition in swift sorting, ascending, descending
猜你喜欢

Summary of common pytoch APIs

Rew acoustic test (I): microphone calibration

Interpretation of source code demand:a rotation equivariant detector for aerial object detection

Opencv learning notes -day13 pixel value statistics calculation of maximum and minimum values, average values and standard deviations (use of minmaxloc() and meanstddev() functions)

QT connection to Shentong database

Talk about how the kotlin process started?

Use Huawei performance management service to configure the sampling rate on demand

Opencv learning notes -day3 (mat object and creation related operations mat:: clone(), mat:: copyto(), mat:: zeros(), mat:: ones(), scalar()...)

Based on svelte3 X desktop UI component library svelte UI

Raspberry pie 4B no screen installation system and networking using VNC wireless projection function
随机推荐
Understanding of MVVM and MVC
Rew acoustic test (I): microphone calibration
技术管理进阶——管理者如何进行梯队设计及建设
How can we get a satisfactory salary? These routines still need to be mastered
[protobuf] protobuf generates cc/h file through proto file
El input limit can only input numbers
Use Huawei performance management service to configure the sampling rate on demand
vite项目require语法兼容问题解决require is not defined
Raspberry pie 4B no screen installation system and networking using VNC wireless projection function
How can I get the discount for opening a securities account? Is online account opening safe?
Evaluation standard for audio signal quality of intelligent speakers
Maxiouassigner of mmdet line by line interpretation
Esp32 (7): I2S and I2C drivers for function development
[kotlin collaboration process] complete the advanced kotlin collaboration process
Occasionally, Flink data is overstocked, resulting in checkpoint failure
Talk about how the kotlin process started?
Flink sql -- No factory implements ‘org. apache. flink. table. delegation. ExecutorFactory‘.
[untitled]
Vite project require syntax compatibility problem solving require is not defined
Be careful of this hole in transmittable thread local