Binder的同步与异步
转载请注明出处:https://blog.****.net/yu8fei/article/details/109389362
这里先介绍一下三个结构体:struct binder_proc proc, struct binder_thread thread, struct binder_node node
-
proc通过threads红黑树保存当前进程中的请求线程thread信息,通过nodes红黑树保存当前进程中实体节点node信息。
-
当前的请求是要交给进程proc中的node所表示的服务进行处理,处理该请求任务的线程为thread
-
同时注意三个队列:proc->todo, thread->todo, node->async_todo,
其中node->async_todo是专门用于存放异步任务的队列,has_async_transaction为0(当前异步队列为空)或1(当前异步队列不为空)
同步及异步任务流程:
-
服务收到同步请求后,会将该同步任务添加至proc->todo
-
服务器收到异步请求后,会根据has_async_transaction的状态:为0则添加至proc->todo并置为1;为1则添加至node->async_todo
-
服务处理完成请求后,会释放buffer数据空间即发送BC_FREE_BUFFER至内核,内核收到后会根据node->async_todo是否为空:不为空则从node->async_todo中取出一个任务添加至thread->todo队列;为空则将has_async_transaction置为0
同步请求和异步请求高并发:
-
同步请求的任务全部添加在proc->todo中;异步请求则最多只有一个任务在proc->todo队列中,其余的全部放在node->async_todo中缓存。然后proc依次取出一个任务并分配空闲线程来处理
-
proc->todo队列中的这一个异步任务分配到的线程为thread,任务处理结束后释放buffer数据空间,这时候会将缓存在node->async_todo异步队列中的任务依次取出一个,再添加到thread->todo中
-
任务执行优先从thread->todo中取出,取出后thread->todo即为空,这时才从proc->todo中取任务。这样做的目的是为了防止过多同步任务导致异步任务被饿死。(若优先从proc->todo中取任务,则thread->todo中的异步任务必须等到proc->todo中的所有任务执行完成,那在大量同步任务的情况下,该异步任务就没有机会处理而被饿死)
结论:
-
客户端通过多个线程T1、T2、T3依次发送Binder同步请求,由于服务器可能分配不同线程来分别执行这些任务,也就无法保证这些任务执行的顺序,所以返回给客户端结果的顺序也无法保证依次为T1、T2、T3。
-
但如果客户端通过多个线程T1、T2、T3依次发送的是Binder异步请求,则服务器端必然是按T1、T2、T3的顺序来执行。