Environment: Flutter SDK v1.5.4-hotfix.1@stable
Corresponding flutter engine: 52 c7a1e849a170be4b2b2fe34142ca2c0a6fea1f
The focus here is on the thread representation of flutter at the C++ layer, not the thread representation at the dart layer
Thread creation
The underlying Thread of flutter (C++) (FML ::Thread) is closely associated with the message loop. That is, each FML ::Thead instance creates an instance of the message loop. Therefore, an FML ::Thread should not be used to create a naked Thread. FML ::Thread internally holds a Thread object using C++11’s STD ::Thread. See the FML ::Thread constructor (thread.cc:25).
The thread runner does two things
- Create message loop instances and associate threads
fml::Thread
object - Of the message loop
TaskRunner
Object and assign it to the threadfml::Thread
That is, the thread also holds oneTaskRunner
The instance
The implementation of FML ::Thread is very simple, but the key is to look at its associated FML ::MessageLoop.
Thread storage
MessageLoop FML ::MessageLoop first uses thread storage to hold a callback. This callback explicitly frees an FML ::MessageLoop memory object.
FML ::ThreadLocal is a thread storage class. The value it stores is an object of type INTPtr_t. FML ::ThreadLocal is implemented differently on different platforms
- The class Linux platform uses library functions for pThread
pthread_key_create
To generate a key key that identifies the thread, the value of which is a helper classBox
It’s savedintptr_t
Object and the callback method passed inThreadLocalDestroyCallback
.ThreadLocal
The keywords that need to be declared before use arestatic
The order of object destructor is slightly convoluted, and the sequence of destructor calls is as follows:
ThreadLocal::~ThreadLocal()
ThreadLocal::Box::~Box()
pthread_key_delete(_key)
ThreadLocal::ThreadLocalDestroy
ThreadLocal::Box::DestroyValue
ThreadLocalDestroyCallback() => [](intptr_t value) {}
MessageLoop::~MessageLoop()
ThreadLocal::Box::~Box()
Copy the code
Cc :27 delete is redundant.
- The Windows platform
ThreadLocal
C++11 standard keywords are used directly before usethread_local
.
Message loop
A message loop is an asynchronous processing model. It blocks the current thread when there is no message to save CPU resources. Otherwise, idling in a polling mode is a waste of CPU resources.
Associated with the thread
See store threads, then in creating FML: : the MessageLoop: when the Thread objects: EnsureInitializedForCurrentThread is very obvious (name though somewhat cumbersome), whether the current Thread to create a message loop object, if not then create and save. So the message loop is associated with the thread, by what? Tls_message_loop This thread storage class object.
The message queue
MessageLoopImpl ::delayed_tasks_ is the actual message queue, which is thread-safe by the mutex_ mutex variable delayed_tasks_mutex_. It looks like a bit of a drag. In fact, it uses a priority queue to insert by execution point, and if the execution point is the same, inserts by FIFO rules.
The queue element is an internal class DelayedTask, which contains the message execution body Task and the execution time target_time. Order is actually used for sorting.
Cycle to achieve
The MessageLoop object constructor creates two important instances, MessageLoopImpl and FML ::TaskRunner, which in turn reference MessageLoopImpl inside FML ::TaskRunner. MessageLoopImpl::Create() creates the body of the MessageLoop corresponding to different platforms, so the relationship between MessageLoop and MessageLoopImpl is clear: MessageLoop is the shell of MessageLoopImpl or the agent of MessageLoop. MessageLoopImpl is an unexposed, platform-related object that truly realizes message reading and processing.
MessageLoopImpl: : Run, the Terminate, WakeUp is pure virtual function, by the platform, For example, the implementation of Android platform MessageLoopAndroid calls ALooper_pollOnce, while MessageLoopLinux calls epoll_wait, a Blocking function of Linux.
The classes and methods involved here are a bit convoluted, but the goal is simple: the operation of reading and processing messages is uniform, but the way threads wake up or block allows platform differences
Send a message
A message loop is associated with a TaskRunner, and the TaskRunner looks at the implementation and finds all the MessageLoopImpl methods, and then contacts the TaskHost created in the AndroidShellHolder constructor. A TaskRunner simply sends messages to a specified message loop, and a message loop is associated with a Thread (FML ::Thread), thus sending messages to a specified Thread (yes, interthread communication). TaskRunner is statement became a thread-safe objects (FML: : RefCountedThreadSafe < TaskRunner >)
So it all sort of comes together: FML ::TaskRunner is similar to android.os.Handler, FML :: Closure is similar to Runnable, FML ::TaskRunner continuously adds various FML :: Closure objects to the message queue and sets the message loop to wake up and execute at a specified point in time.
End of the thread
The FML ::Thread destructor calls its own Join method, which is a bit awkward at first, but the intent is that the calling Thread needs to wait synchronously for the called Thread to finish. The name is not as concise as Exit. The Join method asynchronously sends a request to Terminate the MessageLoop (MessageLoop::GetCurrent().terminate ()), and then blocks until it finishes. Combine the above to list the call sequence for thread exit:
Thread::~Thread() Thread::Join() TaskRunner::PostTask() ... [asynchronous] MessageLoop: : the Terminate () MessageLoopImpl: : DoTerminate MessageLoopImpl: () : the Terminate () = > MessageLoopAndroid::Terminate() ALooper_wake() ... [asynchronous, Function to return] MessageLoopImpl: : Run () = > MessageLoopAndroid: : Run () MessageLoopImpl: : RunExpiredTasksNow () MessageLoopImpl::DoRun() MessageLoop::Run() ... [async] ThreadLocal::~ThreadLocal() [omitted, same as thread storage object destructor call sequence]Copy the code
Thread system
Look back at the constructors of AndroidShellHolder, which involve a flutter::ThreadHost, FML ::TaskRunner, a flutter::TaskRunners, It also creates a series of threads before the Shell object is created: UI_thread, gpu_thread, io_thread, and a series of operations on TaskRunner, which is a bit messy but now very clear.
The thread currently executing the AndroidShellHolder constructor creates a message loop (android_shell_holer.cc :81) and assigns the TaskRunner of the message loop to platform_runner (note: Platform_thread object is not created. The other TaskRunners are TaskRunner objects for the created FML ::Thread Thread.
This raises the question: when a thread sends an asynchronous request through platform_runner, when is it executed?