做工程时遇到需要使用多线程的情况,但没有类似经验。学习一段时间后在此记录供今后参考。
以如下问题为例:cartographer建图时,当在键盘按下按键,则结束建图并保存地图。
在node_main.cc中进行处理。
1、监听键盘事件
#include <thread>
...
namespace {
char generate_map_flag = '\0';
...
void CaptureInputThread()
{
std::cin>>generate_map_flag;
}
...
}
2、新建线程
在执行Run()时,会开辟新的线程监听键盘事件,当按下按键,数据会传送到全局变量generate_map_flag。
void Run() {
std::thread *capture_input_id_;
capture_input_id_ = new std::thread(&CaptureInputThread);
...
}
3、通过全局变量实现线程间交互
新建的线程中键盘事件将键盘信息传入全局变量generate_map_flag,当建图的主线程检测到generate_map_flag满足条件时,执行逻辑。
void Run() {
...
while(ros::ok()){
::ros::spinOnce();
...
if(generate_map_flag == 'g'){
node.FinishAllTrajectories();
node.RunFinalOptimization();
if(node_options.flag_generate_pbstream_map){
time_t now;
struct tm *timenow;
time(&now);
timenow = localtime(&now);
char time_now_str[100];
strftime(time_now_str, 100, "%Y%m%d%H%M%S", timenow);
string time_now = time_now_str;
const string pbstream_filename_ = "/home/cabin/cartographer_map_file/"+time_now+".pbstream";
const string pgm_filename_ = "/home/cabin/cartographer_map_file/"+time_now;
node.SerializeState(pbstream_filename_);
Pbstream_to_ros_map pbstream_to_ros_map;
std::cout<<"generating the map files, please wait ..."<<&std::endl;
pbstream_to_ros_map.pgm_map_build(pbstream_filename_, pgm_filename_,0.05);
generate_map_flag = '\0';
std::cout<<"\n=====================map generate finished=============================\n"<<&std::endl;
}
}
}
...
}
至此,在建图过程中在键盘按下“g”后回车,实现结束建图并保存地图。
代码可能没有完全符合c++标准,但在工程上能实现。后续结合实践的学习希望能进一步掌握多线程,以防出现未知bug并提高程序效率。