Bluedroid线程封装和reactor原理

Bluedroid线程封装和reactor原理

ps:看这篇之前,如果对bluedroid底层数据收发需要进一步了解的,可以看这里:
蓝牙重启case之:hardware error
Bluedroid协议栈BTU线程处理HCI数据流程分析

Bluedroid线程和原始的posix线程有点不一样. posix线程中, 一般使用pthread_create创建一个线程, 然后在线程函数中跑一个while死循环, 处理各自的业务逻辑.传统上, 每个线程处理函数都需要单独编写,并且各不相同.

但在bluedroid中,由于数据处理都是面向消息队列的(基于简单的链表队列,与XSI IPC的消息队列无关,以下都称消息队列). 通过对pthread_create的合理封装后, 并对消息队列使用reactor反射机制,外层应用可以很方便的考虑业务逻辑,而无需关心和实现正常的线程逻辑处理.

一 BlueDroid线程封装

1. 新建一个线程

新建一个线程时(例如hci_thread),建立一个线程内部的消息队列,并且和eventfd 信号量形式的文件描述符关联,然后在线程内部循环等待eventfd信号量, 等到信号量之后, 执行内部的消息队列回调函数, 这个回调函数执行用户自定义的消息队列处理函数.调用完成后, 继续等待eventfd信号量.

thread_t *thread_new_sized(const char *name, size_t work_queue_capacity) {
   
...
  thread_t *ret = osi_calloc(sizeof(thread_t));
a
  ret->reactor = reactor_new();//建立线程内部用的反射器, 创建epoll_fd和event_fd.
    //并把event_fd加入到epoll_fd监测列表中, event_fd主要是停止线程时使用.
...
  ret->work_queue = fixed_queue_new(work_queue_capacity);//线程内部工作队列
...
  // Start is on the stack, but we use a semaphore, so it's safe
  struct start_arg start;
  start.start_sem = semaphore_new(0);
...
  strncpy(ret->name, name, THREAD_NAME_MAX);
  start.thread = ret;
  start.error = 0;
  pthread_create(&ret->pthread, NULL, run_thread, &start);
  semaphore_wait(start.start_sem);
  semaphore_free(start.start_sem);
...
  return ret;
...
}

2. 线程的运行

我们看run_thread线程函数重要func:

  1. 获取线程内部work_queue的dequeue信号量fd, 并在reactor_register函数中, 注册这个fd到epoll集合中.内部work_queue的回调(反射)函数是work_queue_read_cb.
  2. 执行reactor_start(thread->reactor),进入死循环,等待fd信号量. 我们在下一节详细分析反射器reactor的注册(reactor_register)和运行(reactor_start).
static void *run_thread(void *start_arg) {
   
  ...
  struct start_arg *start = start_arg;
  thread_t *thread = start->thread;
  ...
  if (prctl(PR_SET_NAME, (unsigned long)thread->name) == -1) {
   
  ...
  }
  thread->tid = gettid();//线程tid.不是posix线程id.

  LOG_WARN(LOG_TAG, "%s: thread id %d, thread name %s started", __func__, thread->tid, thread->name);

  semaphore_post(start->start_sem);//通知线程已经创建,父线程可以继续往下跑了.

  int fd = fixed_queue_get_dequeue_fd(thread->work_queue);//获取线程内部work_queue的dequeue信号量fd描述符
    //后面的循环中,就是使用多路IO来侦听work_queue的dequeue信号量,并执行用户的消息处理函数.`reactor_register`
  void *context = thread->work_queue;

  reactor_object_t *work_queue_object = reactor_
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值