在上一次,我们了解了域参与者的创建过程。在这一章我们将了解,域参与者是怎么注册类型的。在DDS(数据分发服务,Data Distribution Service)中,类型支持(TypeSupport)类的主要作用是管理和注册数据类型,使得这些数据类型可以在不同的组件之间安全、高效地传输。TypeSupport::register_type
函数的具体功能是将特定的数据类型注册到DDS的领域参与者(DomainParticipant)中,使该数据类型能够被主题(Topic)和数据写入器(DataWriter)等DDS实体使用。
其实现是这一句代码:
type_.register_type(participant_);
这个type_的定义如下:
eprosima::fastdds::dds::TypeSupport type_ = eprosima::fastdds::dds::TypeSupport(new HelloWorldPubSubType());
我们先看看TypeSupport的类定义:
class TypeSupport : public std::shared_ptr<TopicDataType>
TypeSupport接口是一个抽象接口,必须为应用程序使用的每个具体类型进行特化。TypeSupport是DDS数据类型支持的抽象,它封装了与数据类型相关的操作,比如序列化和反序列化。
每个服务的实现都需要提供一种自动生成特定类型类的方法,该方法可以从类型的描述(例如使用OMG IDL映射中的IDL)生成。在可以使用它创建Topic对象之前,必须使用该类型特定类上的register_type操作注册TypeSupport。
其继承自 std::shared_ptr<TopicDataType>
可以将 TypeSupport
对象作为一个智能指针来使用,从而获得 std::shared_ptr
提供的引用计数和内存自动释放等功能。同时他是接受HelloWorldPubSubType()初始化的,而HelloWorldPubSubType与他一样是TopicDataType的子类,意味着TypeSupport
在构建为类的时候,由于接受了HelloWorldPubSubType()内部构建的TopicDataType的指针,可用同时使用->来访问父类TopicDataType的内容,同时他又可以用.来访问类里面的内容。这也是一种组合的实现方式。其实这里public std::shared_ptr<TopicDataType>里面可以不用是父类也可以是其他想要组合的类,在构造函数的时候可以接受一个相同的指针从而达到组合的目的。
他接受赋值构造与移动构造:
* @brief Copy Constructor
*
* @param type Another instance of TypeSupport
*/
FASTDDS_EXPORTED_API TypeSupport(
const TypeSupport& type) noexcept = default;
/**
* @brief Move Constructor
*
* @param type Another instance of TypeSupport
*/
FASTDDS_EXPORTED_API TypeSupport(
TypeSupport&& type) noexcept = default;
同时他也接受:
FASTDDS_EXPORTED_API explicit TypeSupport(
TopicDataType* ptr)
: std::shared_ptr<TopicDataType>(ptr)
{
}
而HelloWorldPubSubType的定义如下
class HelloWorldPubSubType : public eprosima::fastdds::dds::TopicDataType
我们再来看看注册函数的定义:
ReturnCode_t TypeSupport::register_type(
DomainParticipant* participant) const
{
return participant->register_type(*this, get_type_name());
}
他其实是把自身传递给了域参与者的注册函数,同时获取默认的类型名称,或者可以自己指定类型名
ReturnCode_t TypeSupport::register_type(
DomainParticipant* participant,
std::string type_name) const
{
return participant->register_type(*this, type_name.empty() ? get_type_name() : type_name);
}
转到域参与者后又转到了域参与者的具体实现实体去让他干活。
ReturnCode_t DomainParticipant::register_type(
TypeSupport type,
const std::string& type_name)
{
return impl_->register_type(type, type_name);
}
具体函数如下:
ReturnCode_t register_type(
TypeSupport type,
const std::string& type_name)
{
if (type_name.size() <= 0)
{
return RETCODE_BAD_PARAMETER;
}
TypeSupport t = find_type(type_name);
if (!t.empty())
{
if (t == type)
{
return RETCODE_OK;
}
return RETCODE_PRECONDITION_NOT_MET;
}
std::lock_guard<std::mutex> lock(mtx_types_);
types_.insert(std::make_pair(type_name, type));
return RETCODE_OK;
}
这段代码的主要功能就是
- 函数通过调用
find_type
来检查是否已经有一个同名的数据类型被注册。 - 如果
find_type
返回了一个非空的TypeSupport
对象,并且与传入的type
相同,那么该数据类型已经被注册,函数返回RETCODE_OK
。 - 如果
find_type
返回的TypeSupport
对象与传入的type
不同,那意味着已经存在一个不同定义但同名的数据类型,在这种情况下,函数返回RETCODE_PRECONDITION_NOT_MET
。
- 如果
type_name
之前没有被注册,函数将继续进行类型的注册。 - 使用
std::lock_guard<std::mutex>
锁定互斥量mtx_types_
来保证线程安全,以便在多线程环境下安全地修改类型容器types_
。 - 更新类型容器
types_
,将新的类型名称和类型支持对象作为键值对插入到映射中。
至此将方法与函数名注册到types中。