百度自动驾驶apollo源码解读5:cyber的Service踩坑笔记

本文详细介绍了在使用Cyber RT的Service功能时遇到的一个常见问题,即不使用临时变量接收`node->CreateService`返回值导致服务创建失败。分析原因发现,智能指针在没有外部引用时会提前释放,从而使得Service提前析构,无法正常工作。此外,还提到了即使服务已经失效,`cyber_service`命令仍能显示服务存在,这一现象引发的困惑。
摘要由CSDN通过智能技术生成

1.坑描述:不用临时变量接收函数node->CreateService返回值导致服务创建失败

2.前戏:cyber作为ROS的替代品提供了主要两大功能:调度功能和通讯功能.通讯功能包括订阅发布模式和一问一答的Service模式.本篇主要讲的是Service模式下的一个坑.Service的主要实现代码在/cyber/service下面,仅4个文件(两个头文件两个实现文件).可谓相当的精巧.怎么使用呢?源代码里面/cyber/examples/service.cc.50多行代码展示了如何使用他的Service功能.下面展示如何运行这个例子.首先启动控制台进入docker里面.输入命令:

export GLOG_alsologtostderr=1

输入这个是为了让cyber用AINFO等宏产生日志可以直接在控制台看见.接着就可以输入运行命令:

bazel run //cyber/examples:service

此后就可以看到运行输出效果.

3.坑的复现:代码/cyber/examples/service.cc里的第27行写的是

auto server = node->CreateService<Driver, Driver>(....

而后产生的server变量后面没有再被引用.我们将上述代码"auto server = "去掉,重新运行,发现服务启动失败了,客户端始终连接不上去.

4.分析原因:直观的来看很难理解,你这个返回值后来也没用到,我拿不拿变量接收你有什么区别吗?写代码的时候为了简洁起见,反正你后面用不到我就不用拿变量接收你了(我正是干了这种事儿,事后追查了几个小时原因),有什么问题吗?测试的时候就发现客户端始终连接不上,他这这种还不是普通的socket,是高度封装的,正常的socket可以通过工具查看端口的监听情况,以此推断是哪个地方出了问题.后来通过反复的对比发现是忘记了用一个临时变量接收返回值,加上就好了.经过阅读源代码发现是没有用临时变量接受返回值导致智能指针认为自己没有人用了提前释放了.下面举个例子来说明这种情况

#include <iostream>
#include <memory>
class Test
{
public:
	Test() = default;
	virtual ~Test()
	{
		std::cout << "~Test()" << std::endl;
	}
};

auto GetOneTest() 
{
	auto t = std::make_shared<Test>();
	return t;
}

int main(int argc, char **argv)
{
	auto t = GetOneTest();
	std::cout << "main end" << std::endl;
	return 0;
}

编译运行上面的代码,我们看到结果是主函数先结束之后再进行Test的析构.倘若我们将主函数里面的第一行"auto t ="去掉运行结果是先析构Test之后main结束. 言简意赅的总结原因就是:智能指针为自己没有人用了提前释放了,Test实例随之析构.

5.遗留问题:cyber有个插件就做cyber_service, cyber_service list命令可以查看服务列表,令人奇怪的是不用临时变量接收返回值Service提前被析构的情况下该命令仍然可以看到创建的服务.这令我很不理解,误认为服务端没啥问题浪费时间去研究客户端问题.操蛋,有时间再去研究这个事情吧

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值