cartographer源码分析(21)-sensor-ordered_multi_queue.h
来源:互联网 发布:网络错误代码10071 编辑:程序博客网 时间:2024/06/07 06:59
源码可在https://github.com/learnmoreonce/SLAM 下载
文件:sensor/ordered_multi_queue.h#ifndef CARTOGRAPHER_SENSOR_ORDERED_MULTI_QUEUE_H_#define CARTOGRAPHER_SENSOR_ORDERED_MULTI_QUEUE_H_#include <functional>#include <map>#include <memory>#include <string>#include <tuple>#include "cartographer/common/blocking_queue.h"#include "cartographer/common/port.h"#include "cartographer/common/time.h"#include "cartographer/sensor/data.h"namespace cartographer {namespace sensor {struct QueueKey { int trajectory_id;// 轨线id; string sensor_id; //传感器id//重载小于运算符,forward_as_tuple:完美转发. (以tuple规则比较2者),tuple定义了<运算符 bool operator<(const QueueKey& other) const { return std::forward_as_tuple(trajectory_id, sensor_id) < std::forward_as_tuple(other.trajectory_id, other.sensor_id); }};/*OrderedMultiQueue,用于管理多个有序的传感器数据,是有序的多队列类,每个队列有一个key,并且有一个自定义排序函数queues_的形式为:key1:Queuekey2:Queuekey3:QueueQueue的形式为 struct Queue { common::BlockingQueue<std::unique_ptr<Data>> queue; Callback callback; bool finished = false; };OrderedMultiQueue的数据成员有1,common_start_time_per_trajectory_:轨迹id及对应创建轨迹时间2,last_dispatched_time_3,std::map<QueueKey, Queue> queues_;按照key排序的map4,QueueKey blocker_;*/// Maintains multiple queues of sorted sensor data and dispatches(迅速办理) it in merge// sorted order. It will wait to see at least one value for each unfinished// queue before dispatching the next time ordered value across all queues.//// This class is thread-compatible.class OrderedMultiQueue { public: using Callback = std::function<void(std::unique_ptr<Data>)>;//回调函数 OrderedMultiQueue(); ~OrderedMultiQueue();//添加一个【队列】Queue,名称是key,以后入队的data,调用回调函数callback处理 // Adds a new queue with key 'queue_key' which must not already exist. // 'callback' will be called whenever data from this queue can be dispatched. void AddQueue(const QueueKey& queue_key, Callback callback);/*某一key标识的【队列】Queue已经完成入队,因此不能再入队列,并在map中移除key.*/ // Marks a queue as finished, i.e. no further data can be added. The queue // will be removed once the last piece of data from it has been dispatched. void MarkQueueAsFinished(const QueueKey& queue_key);//对某一key标识的队列Queue,压入data,data按照回调函数处理 // Adds 'data' to a queue with the given 'queue_key'. Data must be added // sorted per queue. void Add(const QueueKey& queue_key, std::unique_ptr<Data> data);/*标记全部队列都已经finished. kFirst: {0,4,5,6}kSecond:{0,1,3,7}kThird: {0,2,8}之前只处理到6,调用Flush()则处理剩余的7,8如果不调用Flush(),则析构时会出错 */ // Dispatches all remaining values in sorted order and removes the underlying // queues. void Flush();/*返回阻塞的队列(意为该队列对应的sensor的data未到达)*/ // Must only be called if at least one unfinished queue exists. Returns the // key of a queue that needs more data before the OrderedMultiQueue can // dispatch data. QueueKey GetBlocker() const; private: struct Queue { common::BlockingQueue<std::unique_ptr<Data>> queue; Callback callback; bool finished = false; }; void Dispatch(); void CannotMakeProgress(const QueueKey& queue_key); common::Time GetCommonStartTime(int trajectory_id); // Used to verify that values are dispatched in sorted order. common::Time last_dispatched_time_ = common::Time::min(); std::map<int, common::Time> common_start_time_per_trajectory_; std::map<QueueKey, Queue> queues_;//多队列主体,本类最大的内存占用量 QueueKey blocker_;};} // namespace sensor} // namespace cartographer#endif // CARTOGRAPHER_SENSOR_ORDERED_MULTI_QUEUE_H_/*queues_:first 是QueueKeysecond 是 Queue。Queue的形式为 struct Queue { common::BlockingQueue<std::unique_ptr<Data>> queue; Callback callback; bool finished = false; };*/
文件:ordered_multi_queue.cc#include "cartographer/sensor/ordered_multi_queue.h"#include <algorithm>#include <sstream>#include <vector>#include "cartographer/common/make_unique.h"#include "glog/logging.h"namespace cartographer {namespace sensor {namespace {// Number of items that can be queued up before we log which queues are waiting// for data.const int kMaxQueueSize = 500;} // namespace//重载QueueKey的<<输出运算符,友元函数inline std::ostream& operator<<(std::ostream& out, const QueueKey& key) { return out << '(' << key.trajectory_id << ", " << key.sensor_id << ')';}OrderedMultiQueue::OrderedMultiQueue() {}OrderedMultiQueue::~OrderedMultiQueue() { for (auto& entry : queues_) { CHECK(entry.second.finished); }}//添加一个关键词是key的队列,并用比较函数Callback排序void OrderedMultiQueue::AddQueue(const QueueKey& queue_key, Callback callback) { CHECK_EQ(queues_.count(queue_key), 0); //map.count()相对于[],调用时,是不添加key的。而[]是带有副作用的。c++pr.386 queues_[queue_key].callback = std::move(callback);}void OrderedMultiQueue::MarkQueueAsFinished(const QueueKey& queue_key) { auto it = queues_.find(queue_key); CHECK(it != queues_.end()) << "Did not find '" << queue_key << "'."; auto& queue = it->second; CHECK(!queue.finished);//检查状态 queue.finished = true;//标记本队列已完成,别的数据不能再入队. Dispatch(); //调用一次MarkQueueAsFinished()就要调用一次Dispatch()}//根据key找到队列,并添加data元素void OrderedMultiQueue::Add(const QueueKey& queue_key, std::unique_ptr<Data> data) { auto it = queues_.find(queue_key); if (it == queues_.end()) {//没有key时,警告 LOG_EVERY_N(WARNING, 1000) << "Ignored data for queue: '" << queue_key << "'"; return; } it->second.queue.Push(std::move(data));//Queue的queue.push() Dispatch();//调用一次Add()就要调用一次Dispatch()}//先找到没有finished的队列,然后再对这些队列标记finished.已完成的则不作任何处理void OrderedMultiQueue::Flush() { std::vector<QueueKey> unfinished_queues; for (auto& entry : queues_) { if (!entry.second.finished) { unfinished_queues.push_back(entry.first); } } for (auto& unfinished_queue : unfinished_queues) { MarkQueueAsFinished(unfinished_queue);//一个一个的处理。 }}QueueKey OrderedMultiQueue::GetBlocker() const { CHECK(!queues_.empty()); return blocker_;}/*Dispatch()函数,不断的处理来自sensor的数据。按照data采集的时间顺序处理。kFirst: {1,2,3} finisedkSecond:{} finisedkThird: {} finised*/void OrderedMultiQueue::Dispatch() { while (true) { //首先处理的数据,也即最早采集的数据 const Data* next_data = nullptr; Queue* next_queue = nullptr; QueueKey next_queue_key; //遍历队列中的每一个key:填充上面3个变量值。如果某一key对应的data为空,则直接return for (auto it = queues_.begin(); it != queues_.end();) { const auto* data = it->second.queue.Peek<Data>();//获取某一队的队首data if (data == nullptr) { if (it->second.finished) {//it对应的队列为空且为finished,故删除it对应的key queues_.erase(it++); //map迭代器没有失效? continue; } CannotMakeProgress(it->first);//此时什么也不做。 return; } if (next_data == nullptr || data->time < next_data->time) { //找到next_data数据:即采集时间最早的数据,理论上应该最先处理它。 next_data = data; next_queue = &it->second; next_queue_key = it->first; } CHECK_LE(last_dispatched_time_, next_data->time) << "Non-sorted data added to queue: '" << it->first << "'"; ++it; } if (next_data == nullptr) { CHECK(queues_.empty());//只有多队列为空,才可能next_data==nullptr return; } // If we haven't dispatched any data for this trajectory yet, fast forward // all queues of this trajectory until a common start time has been reached. const common::Time common_start_time = GetCommonStartTime(next_queue_key.trajectory_id); //common_start_time即所有的sensor都开始有data的时间点。 if (next_data->time >= common_start_time) { //大多数情况,happy case // Happy case, we are beyond the 'common_start_time' already. last_dispatched_time_ = next_data->time; next_queue->callback(next_queue->queue.Pop()); //调用回调函数处理data。 } else if (next_queue->queue.Size() < 2) {// 罕见 if (!next_queue->finished) { // We cannot decide whether to drop or dispatch this yet. CannotMakeProgress(next_queue_key); return; } last_dispatched_time_ = next_data->time; next_queue->callback(next_queue->queue.Pop()); } else { // We take a peek at the time after next data. If it also is not beyond // 'common_start_time' we drop 'next_data', otherwise we just found the // first packet to dispatch from this queue. std::unique_ptr<Data> next_data_owner = next_queue->queue.Pop(); if (next_queue->queue.Peek<Data>()->time > common_start_time) { last_dispatched_time_ = next_data->time; next_queue->callback(std::move(next_data_owner)); } } }}void OrderedMultiQueue::CannotMakeProgress(const QueueKey& queue_key) { blocker_ = queue_key; //标识该队列Queue已经阻塞 for (auto& entry : queues_) {//std::map<QueueKey, Queue> if (entry.second.queue.Size() > kMaxQueueSize) {//? LOG_EVERY_N(WARNING, 60) << "Queue waiting for data: " << queue_key; return; } }}/*对同一轨迹id,求得所有sensor的首次采集data的最晚时间maxtime不同轨迹按不同轨迹算:kFirst: {0,1,2,3} finisedkSecond:{2} kThird: {4}{2,2,}*/common::Time OrderedMultiQueue::GetCommonStartTime(const int trajectory_id) { //map.emplace():Construct and insert element,根据trajectory_id构造一个map。 auto emplace_result = common_start_time_per_trajectory_.emplace( trajectory_id, common::Time::min()); common::Time& common_start_time = emplace_result.first->second; if (emplace_result.second) { for (auto& entry : queues_) { //entry是map的pair<,>.本循环求得所有传感器中的maxtime if (entry.first.trajectory_id == trajectory_id) { common_start_time = std::max(common_start_time, entry.second.queue.Peek<Data>()->time); } } LOG(INFO) << "All sensor data for trajectory " << trajectory_id << " is available starting at '" << common_start_time << "'."; } return common_start_time;}} // namespace sensor} // namespace cartographer/*ordered_multi_queue.cc:172] All sensor data for trajectory 0 is available starting at '635727208200176089'*//*LOG_EVERY_N(INFO, 60) << "Queue...";在程序中周期性的记录日志信息,在该语句第1、61、121……次被执行的时候,记录日志信息。*/
.
.
测试代码:ordered_multi_queue_le_test.cc#define sout(Xit) {std::cout<<__LINE__<<" "<< Xit <<""<<std::endl;}#include "cartographer/sensor/ordered_multi_queue.h"#include <vector>#include "cartographer/common/make_unique.h"#include "gtest/gtest.h"namespace cartographer {namespace sensor {namespace {/*测试夹具(Test Fixtures)TEST_F提供了一个初始化函数(SetUp)和一个清理函数(TearDown),在TEST_F中使用的变量可以在初始化函数SetUp中初始化,在TearDown中销毁,并且所有的TEST_F是互相独立的,都是在初始化以后的状态开始运行,一个TEST_F不会影响另一个TEST_F所使用的数据.用TEST_F定义测试,写法与TEST相同,但测试用例名必须为上面定义的类名。*/class OrderedMultiQueueTest : public ::testing::Test { protected: // These are keys are chosen so that they sort first, second, third. const QueueKey kFirst{1, "a"};//trajectory_id,sensor_id const QueueKey kSecond{1, "b"}; const QueueKey kThird{2, "b"};//void AddQueue(const QueueKey& queue_key, Callback callback); void SetUp() { //初始化函数,定义处理data的函数: //(以后用于test比较):检查values_的最大值是否小于欲添加的值. for (const auto& queue_key : {kFirst, kSecond, kThird}) { queue_.AddQueue(queue_key, [this](std::unique_ptr<Data> data) { if (!values_.empty()) { EXPECT_GE(data->time, values_.back().time); } values_.push_back(*data); }); } }//Data的定义在data.h std::unique_ptr<Data> MakeImu(const int ordinal) {//时间,序列 return common::make_unique<Data>( common::FromUniversal(ordinal), Data::Imu{Eigen::Vector3d::Zero(), Eigen::Vector3d::Zero()}); } std::vector<Data> values_; OrderedMultiQueue queue_;};TEST_F(OrderedMultiQueueTest, Ordering) { // void Add(const QueueKey& queue_key, std::unique_ptr<Data> data); queue_.Add(kFirst, MakeImu(0));// queue_.Add(kFirst, MakeImu(4)); queue_.Add(kFirst, MakeImu(5)); queue_.Add(kFirst, MakeImu(6)); EXPECT_TRUE(values_.empty()); //why为空?:queue_对应的其他sensor还没有产生data, //故调用Add()时,只在本队列插入data,而Dispatch()直接返回,没有调用Callback函数。 queue_.Add(kSecond, MakeImu(0)); queue_.Add(kSecond, MakeImu(1)); EXPECT_TRUE(values_.empty()); //同上 queue_.Add(kThird, MakeImu(0)); queue_.Add(kThird, MakeImu(2)); EXPECT_EQ(values_.size(), 4); /*kFirst: {0,4,5,6}kSecond:{0,1}kThird: {0,2}*/ for(auto i:values_) { sout(i.time);//{0,0,0,1} } queue_.Add(kSecond, MakeImu(3)); EXPECT_EQ(values_.size(), 5);/*kFirst: {0,4,5,6}kSecond:{0,1,3}kThird: {0,2}*/ for(auto i:values_) { sout(i.time);//{0,0,0,1,2} } queue_.Add(kSecond, MakeImu(7)); queue_.Add(kThird, MakeImu(8)); /*kFirst: {0,4,5,6}kSecond:{0,1,3,7}kThird: {0,2,8}*/ for(auto i:values_) { sout(i.time);//{0,0,0,1,2,3,4,5,6} }//先找到没有finished的队列,然后再对这些队列标记finished queue_.Flush();//应该调用,否则析构时出错 EXPECT_EQ(11, values_.size());// 4+4+3 /*kFirst: {0,4,5,6}kSecond:{0,1,3,7}kThird: {0,2,8}*/ for(auto i:values_) { sout(i.time);//{0,0,0,1,2,3,4,5,6,7,8} } for (size_t i = 0; i < values_.size() - 1; ++i) { //检查是否按序 EXPECT_LE(values_[i].time, values_[i + 1].time); }}TEST_F(OrderedMultiQueueTest, MarkQueueAsFinished) { queue_.Add(kFirst, MakeImu(1)); queue_.Add(kFirst, MakeImu(2)); queue_.Add(kFirst, MakeImu(3)); EXPECT_TRUE(values_.empty()); queue_.MarkQueueAsFinished(kFirst);//调用该函数一次,就调用一次Dispatch(),若key对应的队列为空,则从队列中删除key EXPECT_TRUE(values_.empty()); queue_.MarkQueueAsFinished(kSecond); EXPECT_TRUE(values_.empty()); queue_.MarkQueueAsFinished(kThird); /*kFirst: {1,2,3} finisedkSecond:{} finisedkThird: {} finised*/ for(auto i:values_) { sout(i.time);//{1,2,3} } EXPECT_EQ(3, values_.size()); for (size_t i = 0; i < values_.size(); ++i) { EXPECT_EQ(i + 1, common::ToUniversal(values_[i].time)); }}TEST_F(OrderedMultiQueueTest, CommonStartTimePerTrajectory) { queue_.Add(kFirst, MakeImu(0)); queue_.Add(kFirst, MakeImu(1)); queue_.Add(kFirst, MakeImu(2)); queue_.Add(kFirst, MakeImu(3)); queue_.Add(kSecond, MakeImu(2)); EXPECT_TRUE(values_.empty()); queue_.Add(kThird, MakeImu(4)); EXPECT_EQ(values_.size(), 2);/*kFirst: {0,1,2,3}kSecond:{2}kThird: {4}*/ for(auto i:values_) { sout(i.time);//{2,2} } queue_.MarkQueueAsFinished(kFirst); EXPECT_EQ(values_.size(), 2);//没有0,1,因为起点时间不是0,1,而是2/*kFirst: {0,1,2,3} finisedkSecond:{2} kThird: {4}*/ for(auto i:values_) { sout(i.time);//{2,2} } sout(".id2.");//为何与test1不同?起点time不同。test1:起点时间全为0,test3起点时间是2 queue_.MarkQueueAsFinished(kSecond); EXPECT_EQ(values_.size(), 4);/*kFirst: {0,1,2,3} finisedkSecond:{2} finisedkThird: {4}*/ for(auto i:values_) { sout(i.time);//{2,2,3,4} }//第二条轨迹id开始采集数据。 queue_.MarkQueueAsFinished(kThird); EXPECT_EQ(values_.size(), 4);/*kFirst: {0,1,2,3} finisedkSecond:{2} finisedkThird: {4} finised*/ for(auto i:values_) { sout(i.time);//{2,2,3,4} }}} // namespace} // namespace sensor} // namespace cartographer
本文发于:
* http://www.jianshu.com/u/9e38d2febec1
* https://zhuanlan.zhihu.com/learnmoreonce
* http://blog.csdn.net/learnmoreonce
* slam源码分析微信公众号:slamcode
阅读全文
0 0
- cartographer源码分析(21)-sensor-ordered_multi_queue.h
- cartographer源码分析(17)-sensor-point_cloud.h
- cartographer源码分析(19)-sensor-range_data.h
- cartographer源码分析(20)-sensor-data.h
- cartographer源码分析(22)-sensor-collator.h
- cartographer源码分析(23)-sensor-voxel_filter.h
- cartographer源码分析(24)-sensor-configuration.h
- cartographer源码分析(18)-sensor-compressed_point_cloud
- cartographer源码分析(3)-common-port.h
- cartographer源码分析(4)-common-time.h
- cartographer源码分析(5)-common-rate_time.h
- cartographer源码分析(6)-common-histogram.h
- cartographer源码分析(7)-common-math.h
- cartographer源码分析(8)-common-make_unique.h
- cartographer源码分析(5)-common-fixed_ratio_sampler.h
- cartographer源码分析(9)-common-mutex.h
- cartographer源码分析(10)-common-thread_pool.h
- cartographer源码分析(11)-common-blocking_queue.h
- #2017 Multi-University Training Contest
- 矩阵中的路径—递归
- 如何向一个Fragment传递参数---setArguments方法的介绍
- 网页打开本地应用程序
- Java学习之ArrayList和LinkedList
- cartographer源码分析(21)-sensor-ordered_multi_queue.h
- ios 基础控件系列之 UIScrollView 初识
- xynu第二次比赛
- jsp基础
- CS231n课程笔记翻译9:卷积神经网络笔记
- 牛客三模-大数据方向:选择题和编程题
- 迷雾——dfs
- 齐次含义
- 如何进行反向迭代以及如何实现反向迭代