cartographer关键组件之线程池

1. 概述

线程池就是提前创建了多个线程,这些线程被保存在所谓的"池子"中,同时还有一个任务队列,保存所有需要被执行的任务,然后通过调度,将任务分配给"池子"中的每一个线程进行执行,从而提高并发效率。

cartographer的线程池由两个类构成——
1、线程池 ThreadPool (src/cartographer/cartographer/common/thread_pool.h)
2、任务 Task (src/cartographer/cartographer/common/task.h)

结构图如下:
在这里插入图片描述

2. 关键问题

2.1 线程如何构建

线程池在构造函数中创建所有的线程:

// 根据传入的数字, 进行线程池的构造, DoWork()函数开始了一个始终执行的for循环
ThreadPool::ThreadPool(int num_threads) {
  CHECK_GT(num_threads, 0) << "ThreadPool requires a positive num_threads!";
  absl::MutexLock locker(&mutex_);
  // std::vector<std::thread> pool_
  for (int i = 0; i != num_threads; ++i) {
    pool_.emplace_back([this]() { ThreadPool::DoWork(); });
  }
}

线程启动后所运行的任务是 ThreadPool::DoWork()。

2.2 任务如何执行

每个独立的线程在各自的ThreadPool::DoWork()中执行任务,首先去task_queue_中取任务,cartographer的线程池一个比较有意思的设计是,考虑了任务的依赖性,把可以立即执行的任务放置到task_queue_中,而存在依赖的任务放置到tasks_not_ready_中。

2.3 任务的添加

任务的添加是在ThreadPool的Schedule函数里完成的,不过会先将任务添加到tasks_not_ready_中,然后在之后会判断该任务是否具有依赖,如果没依赖就会将该任务从tasks_not_ready_提取到task_queue_中,从而可以被正常执行。

2.4 任务依赖状态的转变

所谓的依赖也就是该任务需要等待另一个任务完成后才能执行,通过:

void Task::AddDependency(std::weak_ptr<Task> dependency)

添加依赖,然后 1、该任务的依赖数量+1(++uncompleted_dependencies_)
2、告知被依赖的任务 “完成后请通知我” (shared_dependency->AddDependentTask(this))

当该被依赖任务执行完毕后,会调用依赖该任务的每一个其他任务的 void Task::OnDependenyCompleted()函数 告知 “我已经完成”,此后,这些依赖该任务的其他任务各自的依赖数变量减1,当依赖数减为0时,调用void ThreadPool::NotifyDependenciesCompleted(Task* task),将该任务从线程池的tasks_not_ready_移动到task_queue_,从而可被正常调度执行,具体请看上面的结构图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值