05.Binder系统:第6课第9节_Binder系统_server的多线程实现

在binder系统中,由一个server进程提供服务,有一个或者多个client向他发送服务请求,并且是有可能同时发生请求的,假若client进程非常的多,server进程忙不过来怎么办呢?

忙不过来时,创建多线程,由这些线程处理这些服务。那么怎么才能判断他忙不过来?通过前面的小节我们知道,对于每一个进程都存在一个binder_proc,binder_proc中有一个todo链表,当client发送请求的时候,会把数据放入到todo链表,并且唤醒等待在todo这个链表上的线程,如果有线程在wait这里等待,则代表忙得过来,如果没有一个线程在等待,就代表已经忙不过来了,下图四个简要框图:
在这里插入图片描述

这个时候,驱动程序就会向server进程发出相应,告诉server进程需要创建更多的线程。
1.是在驱动程序中判断,是否忙得过来。
2.驱动程序向APP发出请求,创建新线程。
3.APP创建新线程

围绕着上面3点我们去查看源代码(SDK/kernel/driver/android/binder.c),找到其中的binder_thread_read函数,在该函数的最末尾部分,可以看到如下代码:


binder_inner_proc_lock(proc);
	

	/*当proc->requested_threads == 0:未处理的新线程请求,list_empty(&thread->proc->waiting_threads):等待的线程为0时,
	proc->requested_threads_started < proc->max_threads:已经启动的线程数,小于设定的最大值*/
	if (proc->requested_threads == 0 &&
	    list_empty(&thread->proc->waiting_threads) &&
	    proc->requested_threads_started < proc->max_threads &&
	    (thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
	     BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
	     /*spawn a new thread if we leave this out */) {
	     /*线程数目+1,当新线程运行完成的时候-1*/
		proc->requested_threads++;
		binder_inner_proc_unlock(proc);
		binder_debug(BINDER_DEBUG_THREADS,
			     "%d:%d BR_SPAWN_LOOPER\n",
			     proc->pid, thread->pid);
		/*发送一个创建线程的请求给应用程序*/
		if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
			return -EFAULT;
		binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
	} else
		binder_inner_proc_unlock(proc);

其作用就是判断是否发送创建新线程的请求。驱动程序向APP发出"创建新线程请求"的条件:
1.proc->requested_threads == 0(未处理的新线程请求)
2.list_empty(&thread->proc->waiting_threads):等待的线程为0
3.proc->requested_threads_started < proc->max_threads:已经启动的线程数,小于设定最大值数max_threads

在发送请求之后,会执行proc->requested_threads++,当应用程序调用新线程,进行写操作时,会执行proc->requested_threads–。如下:

static int binder_thread_write(struct binder_proc *proc,struct binder_thread *thread,binder_uintptr_t binder_buffer, size_t size,binder_size_t *consumed)
	case BC_REGISTER_LOOPER:
		/*未处理的线程数*/
		proc->requested_threads--;
		/*启动的线程数目+1*/
		proc->requested_threads_started++;
		

表示新的线程已经进入了循环体。

那么我们怎么去写应用程序呢?
1.设置max_threads,如果未设定,默认值为0
2.收到BR_SPAWN_LOOPER时,创建新线程。
3.新线程要执行一个ioctl,发送BC_REGISTER_LOOPER给驱动程序,告诉其已经进入循环体了
4.像主线程一样进入一个循环体:read-driver,处理。

猜你喜欢

转载自blog.csdn.net/weixin_43013761/article/details/89011403