3. Binder线程管理
任务说明
本案例实现Binder驱动中用于处理进程间调用的事务线程池管理模块,核心目标包括:维护线程池空闲列表与活跃线程计数、按需创建新线程、在线程完成任务后回收并允许退出。该模块是Binder IPC中binder_thread生命周期管理的基础设施,聚焦于线程的创建与退出策略,不涉及具体事务路由逻辑。
核心数据结构
/* 线程状态 */
#define BINDER_THREAD_IDLE 0
#define BINDER_THREAD_ACTIVE 1
#define BINDER_THREAD_EXITING 2
struct binder_thread_node {
int tid;
int state;
struct binder_thread_node *next;
};
struct binder_thread_pool {
struct binder_thread_node *idle_list; /* 空闲线程链表 */
int total_threads; /* 当前线程总数 */
int active_threads; /* 活跃线程数 */
int max_threads; /* 线程上限 */
int min_idle_threads; /* 保持的最小空闲数 */
};
关键完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BINDER_THREAD_IDLE 0
#define BINDER_THREAD_ACTIVE 1
#define BINDER_THREAD_EXITING 2
struct binder_thread_node {
int tid;
int state;
struct binder_thread_node *next;
};
struct binder_thread_pool {
struct binder_thread_node *idle_list;
int total_threads;
int active_threads;
int max_threads;
int min_idle_threads;
};
/* 初始化线程池 */
void binder_pool_init(struct binder_thread_pool *pool, int max, int min_idle)
{
pool->idle_list = NULL;
pool->total_threads = 0;
pool->active_threads = 0;
pool->max_threads = max;
pool->min_idle_threads = min_idle;
}
/* 创建新线程节点 */
static struct binder_thread_node *binder_thread_create(struct binder_thread_pool *pool, int tid)
{
struct binder_thread_node *node;
if (pool->total_threads >= pool->max_threads)
return NULL;
node = (struct binder_thread_node *)malloc(sizeof(*node));
if (!node)
return NULL;
node->tid = tid;
node->state = BINDER_THREAD_IDLE;
node->next = NULL;
pool->total_threads++;
return node;
}
/* 将线程加入空闲列表 */
static void binder_thread_add_idle(struct binder_thread_pool *pool,
struct binder_thread_node *node)
{
node->state = BINDER_THREAD_IDLE;
node->next = pool->idle_list;
pool->idle_list = node;
}
/* 从空闲列表摘除一个线程 */
static struct binder_thread_node *binder_thread_remove_idle(struct binder_thread_pool *pool)
{
struct binder_thread_node *node = pool->idle_list;
if (!node)
return NULL;
pool->idle_list = node->next;
node->next = NULL;
return node;
}
/* 获取一个可用线程:优先复用空闲线程,否则创建新线程 */
struct binder_thread_node *binder_thread_get(struct binder_thread_pool *pool)
{
struct binder_thread_node *node;
node = binder_thread_remove_idle(pool);
if (!node) {
/* 尝试创建新线程,tid用当前总数+1模拟内核分配 */
node = binder_thread_create(pool, pool->total_threads + 1);
if (!node)
return NULL;
}
node->state = BINDER_THREAD_ACTIVE;
pool->active_threads++;
return node;
}
/* 线程完成工作后归还:若空闲线程过多则标记退出并释放 */
void binder_thread_put(struct binder_thread_pool *pool, struct binder_thread_node *node)
{
int idle_count = 0;
struct binder_thread_node *cur;
/* 统计当前空闲数 */
for (cur = pool->idle_list; cur; cur = cur->next)
idle_count++;
if (idle_count >= pool->min_idle_threads) {
/* 空闲线程已足够,允许该线程退出 */
node->state = BINDER_THREAD_EXITING;
pool->total_threads--;
free(node);
} else {
/* 需要保留该线程作为空闲线程 */
binder_thread_add_idle(pool, node);
}
pool->active_threads--;
}
/* 打印线程池状态 */
void binder_pool_dump(struct binder_thread_pool *pool)
{
struct binder_thread_node *cur;
printf("total=%d active=%d idle_list: ", pool->total_threads, pool->active_threads);
for (cur = pool->idle_list; cur; cur = cur->next)
printf("[tid:%d] ", cur->tid);
printf("\n");
}
/* 模拟工作负载:获取线程、执行、归还 */
void binder_pool_simulate_work(struct binder_thread_pool *pool, int work_items)
{
int i;
struct binder_thread_node *workers[10];
int worker_cnt = 0;
for (i = 0; i < work_items && i < 10; i++) {
workers[worker_cnt] = binder_thread_get(pool);
if (!workers[worker_cnt]) {
printf("work item %d: failed to get thread (pool full)\n", i);
break;
}
printf("work item %d: got thread tid=%d\n", i, workers[worker_cnt]->tid);
worker_cnt++;
}
/* 模拟执行完毕,归还线程 */
for (i = 0; i < worker_cnt; i++)
binder_thread_put(pool, workers[i]);
}
/* 验证入口 */
int main(void)
{
struct binder_thread_pool pool;
struct binder_thread_node *t1, *t2;
binder_pool_init(&pool, 4, 1); /* 最大4线程,保持至少1个空闲 */
printf("=== 初始状态 ===\n");
binder_pool_dump(&pool);
printf("\n=== 获取2个线程 ===\n");
t1 = binder_thread_get(&pool);
t2 = binder_thread_get(&pool);
printf("t1 tid=%d, t2 tid=%d\n", t1->tid, t2->tid);
binder_pool_dump(&pool);
printf("\n=== 归还t1(空闲数0<1,应保留为空闲) ===\n");
binder_thread_put(&pool, t1);
binder_pool_dump(&pool);
printf("\n=== 归还t2(空闲数1>=1,应退出释放) ===\n");
binder_thread_put(&pool, t2);
binder_pool_dump(&pool);
printf("\n=== 模拟5个并发工作项 ===\n");
binder_pool_simulate_work(&pool, 5);
binder_pool_dump(&pool);
printf("\n=== 模拟超过上限的工作项 ===\n");
binder_pool_simulate_work(&pool, 6);
binder_pool_dump(&pool);
return 0;
}
编译与运行
gcc -o binder_thread_pool binder_thread_pool.c
./binder_thread_pool
验证方法与判定标准
程序输出应满足以下条件即判定通过:
- 初始状态
total=0 active=0,空闲列表为空。 - 获取2个线程后
total=2 active=2,两个线程tid分别为1和2。 - 归还t1后,由于空闲数0小于
min_idle_threads=1,t1进入空闲列表,total=2 active=1。 - 归还t2后,空闲数1不小于1,t2被释放退出,
total=1 active=0,空闲列表仅剩t1。 - 模拟5个工作项时,前4个成功获取线程(tid 2,3,4,5),第5个因达到
max_threads=4获取失败,输出failed to get thread。 - 所有工作项归还后,空闲线程数维持在
min_idle_threads=1,多余线程被回收,total最终为1。
线程状态流转
关键机制说明
- 线程获取:
binder_thread_get()优先从空闲列表摘取线程,若空闲列表为空且未达max_threads上限则新建线程;两者均失败时返回NULL,调用方需自行处理(如阻塞等待或返回错误)。 - 线程归还:
binder_thread_put()根据当前空闲线程数决定线程去留——空闲数不足min_idle_threads时保留为空闲线程,否则标记退出并释放内存,实现动态伸缩。 - 模拟验证:
main()中的工作负载模拟展示了线程从创建、复用、保留到回收的完整生命周期,可直接观察线程池容量变化。