OMG Data Distribution Service(DDS)规范解读-Part3

2.以数据为中心的订阅发布(DCPS)

2.2 平台无关模型(Platform Independent Model ,PIM)

2.2.2 平台无关模型(PIM)描述

2.2.2.4 Publication Module

由以下类组成:

  • Publisher
  • DataWriter
  • PublisherListener
  • DataWriterListener

publication module

2.2.2.4.1 Publisher Class

发布者(Publisher)代表属于它的一个或多个数据写入者(DataWriter)对象。当其中一个DataWriter对象关联的数据发生改变时,发布者决定何时真正发送数据更新消息。在做出此决定时,发布者会考虑与数据有关的(时间戳,写入者等)以及与发布者(Publisher)和数据写入者(DataWriter)的QoS有关的额外信息,根据这些信息判断何时执行数据发送或者取消数据发送。

  1. set_listener (from Entity):通过扩展实体(Entity)类,发布者(Publisher)可以在创建时或创建后使用set_listener方法将其与监听器(Listener)进行绑定。附加的Listener必须继承自PublisherListener。
  2. get_listener (from Entity):获取Publisher附加绑定的PublisherListener。
  3. set_qos (来自实体类Entity)
  4. get_qos (来自实体类Entity)
  5. create_ datawriter:将创建一个DataWriter。返回的DataWriter将附加并属于此Publisher。
  • 通过主题(Topic)对象的get_qos方法获取关联主题(Topic)的QoS策略。
  • 通过Publisher对象的get_default_datawriter_qos方法获取默认的DataWriter QoS。
  • 结合上述两种QoS策略,根据需要有选择地修改。
  • 使用生成的QoS策略创建DataWriter。
DataWriter* Publisher::create_datawriter(
        Topic* topic,
        const DataWriterQos& qos,
        DataWriterListener* listener,
        const StatusMask& mask)
{
    
    
    return impl_->create_datawriter(topic, qos, listener, mask);
}

上面代码中的实现如下:

DataWriter* PublisherImpl::create_datawriter(
        Topic* topic,
        const DataWriterQos& qos,
        DataWriterListener* listener,
        const StatusMask& mask)
{
    
    
    EPROSIMA_LOG_INFO(PUBLISHER, "CREATING WRITER IN TOPIC: " << topic->get_name());
    //Look for the correct type registration
    TypeSupport type_support = participant_->find_type(topic->get_type_name());

    /// Preconditions
    // Check the type was registered.
    if (type_support.empty())
    {
    
    
        EPROSIMA_LOG_ERROR(PUBLISHER, "Type: " << topic->get_type_name() << " Not Registered");
        return nullptr;
    }

    if (!DataWriterImpl::check_qos_including_resource_limits(qos, type_support))
    {
    
    
        return nullptr;
    }

    DataWriterImpl* impl = create_datawriter_impl(type_support, topic, qos, listener);
    return create_datawriter(topic, impl, mask);//进到下面create_datawriter(topic, impl, mask)的方法,在下面的方法里面返回一个DataWriter
}
DataWriterImpl* PublisherImpl::create_datawriter_impl(
        const TypeSupport& type,
        Topic* topic,
        const DataWriterQos& qos,
        DataWriterListener* listener)
{
    
    
    return new DataWriterImpl(this, type, topic, qos, listener);
}
DataWriter* PublisherImpl::create_datawriter(
        Topic* topic,
        DataWriterImpl* impl,
        const StatusMask& mask)
{
    
    
    topic->get_impl()->reference();

    DataWriter* writer = new DataWriter(impl, mask);
    impl->user_datawriter_ = writer;

    {
    
    
        std::lock_guard<std::mutex> lock(mtx_writers_);
        writers_[topic->get_name()].push_back(impl);
    }

    if (user_publisher_->is_enabled() && qos_.entity_factory().autoenable_created_entities)
    {
    
    
        if (ReturnCode_t::RETCODE_OK != writer->enable())
        {
    
    
            delete_datawriter(writer);
            return nullptr;
        }
    }

    return writer;
}
  1. delete_datawriter:删除属于Publisher的DataWriter。必须在创建DataWriter的同一Publisher对象上调用delete_datawriter方法。如果在另一个Publisher上调用delete_datawriter,该方法将不起作用,并返回PRECONDITION_NOT_MET。
  2. lookup_datawriter:查找获取之前创建成功的属于发布者(Publisher)的DataWriter
  3. suspend_publications:告知DDS服务,应用程序将利用属于本Publisher的DataWriter对象进行多次修改。使用此方法必须有匹配的resume_publications方法调用,表明修改集合已完成。如果在调用resume_publications之前删除了发布者,则将丢弃尚未发布的所有暂停更新。
  4. resume_publications:告知服务,应用程序已完成之前suspend_publications方法启动的多个修改。
  5. begin_coherent_changes 要求应用程序使用属于Publisher的DataWriter对象开始“一致集”的修改。 “一致集”将使用匹配的end_coherent_changes方法调用来完成。
  6. wait_for_acknowledgments:此方法会阻塞调用线程,直到所有匹配的可靠的DataReader实体都确认收到可靠的DataWriter实体写入的所有数据,或者max_wait参数设定的持续时间已经到期,以先发生者为准。返回值为OK表示所有匹配的可靠的数据读取者已确认收到所有写入的数据样本; 返回值TIMEOUT表示在确认收到所有数据之前已经超过max_wait设定的时间周期。
  7. get_participant:返回发布者Publisher所属的DomainParticipant。
  8. delete_contained_entities:将删除通过Publisher对象“创建”的所有DataWriter对象。
  9. set_default_datawriter_qos:设置DataWriter QoS策略的默认值。在create_datawriter方法使用默认QoS策略的情况下,该策略值将用于新创建的DataWriter实体。
  10. get_default_datawriter_qos:获取DataWriter QoS的默认值
  11. copy_from_topic_qos:此方法将a_topic_qos中的策略复制到a_datawriter_qos中的相应策略(即替换a_datawriter_qos中的值,如果该位置存在值)
2.2.2.4.2 DataWriter Class
  • DataWriter类允许应用程序设置给定Topic下发布的数据的值。
  • DataWriter只附加到一个充当它的工厂的Publisher。
  • DataWriter只与一个主题(Topic)绑定,因此只与一种数据类型绑定。主题(Topic)必须在DataWriter创建之前存在。
  • DataWriter是一个抽象类。
  1. set_listener (from Entity):DataWriter可以在创建时或创建后使用set_listener方法将其与监听器(Listener)进行绑定。
  2. get_listener (from Entity):获取DataWriterListener
  3. set_qos (from Entity):设置QoS
  4. get_qos (from Entity):获取QoS
  5. register_instance:注册实例。通知服务应用程序将修改特定数据实例。它将一个实例(用于获取关键字值)作为参数,并返回一个可用于连续写入或处理数据的方法的句柄。
  6. register_instance_w_timestamp:在应用程序希望指定source_timestamp值的情况下,可以代替register_instance
  7. unregister_instance:通知服务DataWriter不打算再修改该数据实例。此操作还表明服务可以在本地删除有关该实例的所有信息。如果在此之后,应用程序想要修改(写入或处置)实例,它必须再次注册它,或者使用特殊的句柄值HANDLE_NIL。此操作并不表示实例已被删除(这是Dispose要做的事情)。unregister_instance操作只是指示DataWriter不再有关于该实例的“任何内容要说”。
  8. unregister_instance_w_timestamp:在应用程序希望指定source_timestamp值的情况下,可以代替unregister_instance
  9. get_key_value:检索和instance_handle相关的实例key值,该操作将仅填充KEY_HOLDER实例内构成密钥的字段。
  10. lookup_instance:把instance作为参数传进去,返回一个句柄,实例参数仅用于检查定义键的字段。
  11. write:该方法能够修改data instance的值,当这个方法被调用的时候 ,服务将通过SampleInfo中的SOURCE_TIMESTAMP属性自动提供可供DataReader对象使用的SOURCE_TIMESTAMP的值。
    必须在为正在写入的特定应用程序数据类型生成的专用类上提供此操作。这样,保存数据的数据参数具有正确的应用程序定义类型(例如,‘foo’)。
    此操作断言DataWriter本身、发布者和DomainParticipant上的活跃性。
    特定值HANDLE_NIL可用于参数HANDLE。这表明实例的标识应该自动从INSTANCE_DATA(通过key)推断出来。
    如果handle是除了HANDLE_NIL以外的任意值,则它必须对应于注册实例(由其key标识)时由REGISTER_INSTANCE返回的值。不然将执行以下操作:
    1.如果句柄对应于现有实例,但不对应于‘data’参数引用的相同实例,则行为通常是未指定的,但如果服务实现可以检测到,则操作将失败并返回错误代码PRECONDITION_NOT_MET。
    2.如果句柄与现有实例不对应,则行为通常未指定,但如果服务实现可以检测到,则操作将失败并返回错误代码BAD_PARAMETER。
    如果 RELIABILITY 的 kind 设置成了RELIABLE,则如果修改会导致数据丢失或导致超过RESOURCE_LIMITS中指定的限制之一,则write操作可能会被上锁。在这些情况下,可靠性max_block_time配置写入操作可能阻止的等待空间变得可用的最长时间。如果max_blocking_time在datawer能够存储修改而不超过限制之前失效,写操作将失败并返回TIMEOUT。
    即使HISTORY 的kind 是 KEEP_LAST,DataWriter write操作也会在以下情况下被阻塞:
    • If (RESOURCE_LIMITS max_samples < RESOURCE_LIMITS max_instances * HISTORY depth), then in the
    situation where the max_samples resource limit is exhausted the Service is allowed to discard samples of some other
    instance as long as at least one sample remains for such an instance. If it is still not possible to make space available to
    store the modification, the writer is allowed to block.
    • If (RESOURCE_LIMITS max_samples < RESOURCE_LIMITS max_instances), then the DataWriter may block
    regardless of the HISTORY depth.
    满足以下两个条件也会返回错误码OUT_OF_RESOURCES而不是阻塞:
    1.阻塞的原因可能是超出了RESOURCE_LIMITS
    2.服务决定等待max_waiting_time,没有机会释放资源

如果提供的handle是有效的,对于一个现有的实例,但不对应于由data参数引用的相同实例,行为是未指定的,但如果被 Service implementation检测到,返回错误代码PRECONDITION_NOT_MET。如果提供的handle是无效的,返回错误代码为BAD_PARAMETER

  1. write_w_timestamp:操作和write一致,多提供了source_timestamp
  2. dispose :请求删除该数据(实际被删除是在整个系统不再使用该数据为止),服务自动提供了source_timestamp的值
  3. dispose_w_timestamp:由应用程序提供source_timestamp的值
  4. wait_for_acknowledgments:只有在DataWriter 的QoS设置成RELIABILITY且 kind设置为RELIABLE时才可以使用,否则将立即返回RETCODE_OK。wait_for_acknowledgments将阻塞调用线程,直到DataWriter所有匹配的具有QoS=RELIABILITY的DataReader 确认,或max_wait参数指定的时间超时。返回值为OK表示所有样本都已经被DataReader 确认。
  5. get_liveliness_lost_status:允许访问LIVELINESS_LOST 的通信状态
  6. get_offered_deadline_missed_status
  7. get_offered_incompatible_qos_status
  8. get_publication_matched_status
  9. get_topic:返回与 DataWriter相关的Topic,与创建 DataWriter时的一样
  10. get_publisher:返回这个 DataWriter附属的Publisher
  11. assert_liveliness:断言DataWriter的liveliness
  12. get_matched_subscription_data:检索与当前DataWriter关联的订阅信息。如订阅信息有匹配的topic和QoS,但应用程序没有指示,应该被忽略(使用DomainParticipant ignore_subscription)
  13. get_matched_subscriptions:检索与当前DataWriter关联的订阅列表。如订阅列表中有匹配的topic和QoS,但应用程序没有指示,应该被忽略(使用DomainParticipant ignore_subscription)
2.2.2.4.3 PublisherListener接口
2.2.2.4.4 DataWriterListener 接口
2.2.2.5 Subscription Module

Subscriptionmodule
由以下类组成:
• Subscriber
• DataReader
• DataSample
• SampleInfo:样本信息
• SubscriberListener
• DataReaderListener
• ReadCondition
• QueryCondition:查询条件

2.2.2.5.1 数据的访问

DataReader 使用: read, read_w_condition, take,
和 take_w_condition操作来获得数据。read操作是指应用程序只能得到对应的数据,可以多次读取。take操作代表应用程序对数据负全部责任,DataReader不再能够访问该数据。DataReader可以多次访问同一个sample,但是前提是之前的访问都是read

这些操作每个都返回Data和相关的SampleInfo

2.2.2.5.1.1 Interpretation of the SampleInfo
struct SampleInfo
{
    
    
    //! indicates whether or not the corresponding data sample has already been read
    SampleStateKind sample_state;

    //! indicates whether the DataReader has already seen samples for the most-current generation of the related instance.
    ViewStateKind view_state;

    //! indicates whether the instance is currently in existence or, if it has been disposed, the reason why it was disposed.
    InstanceStateKind instance_state;

    //! number of times the instance had become alive after it was disposed
    int32_t disposed_generation_count;

    //! number of times the instance had become alive after it was disposed because no writers
    int32_t no_writers_generation_count;

    //! number of samples related to the same instance that follow in the collection
    int32_t sample_rank;

    //! the generation difference between the time the sample was received, and the time the most recent sample in the collection was received.
    int32_t generation_rank;

    //! the generation difference between the time the sample was received, and the time the most recent sample was received.
    //! The most recent sample used for the calculation may or may not be in the returned collection
    int32_t absolute_generation_rank;

    //! time provided by the DataWriter when the sample was written
    fastrtps::rtps::Time_t source_timestamp;

    //! time provided by the DataReader when the sample was added to its history
    fastrtps::rtps::Time_t reception_timestamp;

    //! identifies locally the corresponding instance
    InstanceHandle_t instance_handle;

    //! identifies locally the DataWriter that modified the instance
    //!
    //! Is the same InstanceHandle_t that is returned by the operation get_matched_publications on the DataReader
    InstanceHandle_t publication_handle;

    //! whether the DataSample contains data or is only used to communicate of a change in the instance
    bool valid_data;

    //!Sample Identity (Extension for RPC)
    fastrtps::rtps::SampleIdentity sample_identity;

    //!Related Sample Identity (Extension for RPC)
    fastrtps::rtps::SampleIdentity related_sample_identity;

};

  • 上面代码里面SampleStateKind sample_state;SampleStateKind 有两个值,READ or NOT_READ。
  • 上面代码里面InstanceStateKind instance_state;InstanceStateKind 有三个值,ALIVE,
    NOT_ALIVE_DISPOSED or NOT_ALIVE_NO_WRITERS.
  • 上面代码里面bool valid_data;有些DataSample只有SampleInfo但没有关联的Data,通过检查valid_data的值来区分DataSample是否有数据,TRUE则表示包含有效数据,FALSE表示不包含数据。先检查valid_data,如果是FALSE,那么直访问SampleInfo,不访问Data。
  • 上面代码里面int32_t disposed_generation_count;int32_t no_writers_generation_count;关联到每一个DataReader,这两个计时器初始都被设置成0。当对应实例的instance_state 从NOT_ALIVE_DISPOSED切换成ALIVE,disposed_generation_count加一,当对应实例的instance_state 从ALIVE切换成NOT_ALIVE_DISPOSED,no_writers_generation_count加一。
  • 上面代码里面int32_t sample_rank;int32_t generation_rank;int32_t absolute_generation_rank; sample_rank 和generation_rank 是根据read 或 take返回的有序集合中的实际样本来计算的。sample_rank 指的是在当前instance之后的同一个instance的sample数量。generation_rank 表示从接收sample到接收MRSIC的时间内instance从not-alive 到 alive的次数。absolute_generation_rank代表从接收到sample到调用read或take的时间内从not-alive 到 alive的次数。
  • 所有的counter和rank都是为了区分属于instance的不同“代”sample。
  • ViewStateKind view_state;:值:NEW or NOT_NEW。NEW:DataReader第一次访问该instance的sample,或DataReader访问了该instance之前的sample,但是该instance已经重生了。NOT_NEW:DataReader访问了该instance之前的sample,instance还没重生。
2.2.2.5.1.9 Data access patterns

应用程序获取数据是通过在DataReader上执行read或take操作。这些操作会返回一个包含了sampleInfo和Data的DataSample。这些都是建立在QoS(DataReader和Subscriber)、时间戳、read/take操作的参数的基础上的。read/take操作是非阻塞的,只是传递当前可用的、匹配指定状态的数据。
read_w_condition 和 take_w_condition用ReadCondition代替了sample, view 和 instance states这些参数。只有当ReadCondition = TRUE时这些sample才会有return。这些操作和ReadCondition objects和WaitSet结合在一起,允许执行等待读取。

2.2.2.5.2 Subscriber类

Subscriber通过与其关联的DataReader进行操作,当接收数据的时候,会建立相关的DataReader列表,通过listener或者启用相关条件向应用程序只是data是可用的。应用程序可通过 get_datareaders 访问DataReader列表,通过对DataReader的操作访问可用的data。
在这里插入图片描述在这里插入图片描述

  1. get_datareaders:能够得到DataReader,包含sample_states, view_states, and instance_states
  2. notify_dataread:在DataReaderListener上调用on_data_available ,该操作会附加在DataReader上,DATA_AVAILABLE 的状态会改变。这个操作通常从 SubscriberListener 的on_data_on_readers中进行调用,这样,SubscriberListener 就可以把数据处理委托给DataReaderListener。
  3. get_sample_lost_status:获取sample_lost的通信状态
  4. copy_from_topic_qos:将a_topic_qos 复制到 a_datareader_qos
2.2.2.5.2 DataReader 类

在这里插入图片描述
2
3
4

  1. create_readcondition:建一个create_readcondition,属于DataReader,失败会返回nil
  2. create_querycondition:建一个create_querycondition,属于DataReader,失败会返回nil
  3. delete_readcondition
  4. read:从DataReader获取Data数据, sample之间的顺序与DESTINATION_ORDERQoS是一致的。read操作用到了SampleInfo。data_values和sample_info集合的初始属性决定了read操作的准确行为。集合有三个属性:the current-length (len), the maximum length (max_len), and whether the collection container owns the memory of the elements within (owns)

max_samples:The size of the returned collection will be limited to the specified max_samples.
max_len = data_values.maximum()

  • check一下两个集合的len,max_len,owns,这些值必须相同
  • 成功输出时,len,max_len,owns,这些值相同
  • 如果输入的max_len= =0,data_values和sample_info集合将向DataReader借(loaned)一些元素。owns就会被设置成FALSE,len会被设置成values返回的数量,max_len被设置成验证 max_len >= len的值。允许对数据的零拷贝,应用程序需要使用return_loan将loan还给DataReader
  • 如果输入的max_len > 0,且own == FALSE,read会失败,返回PRECONDITION_NOT_MET
  • 如果输入的max_len > 0,且own == TRUE,read会将Data和SampleInfo拷贝到集合中。输出的时候,own = TRUE,len是拷入的值的大小,max_len不变。可以控制copy,app可以控制copy的位置,app还不用还loan。sample的copy取决于max_len 和max_samples:
    【1】max_samples = LENGTH_UNLIMITED:最多copy max_len个值
    【2】max_samples <= max_len:最多copy max_samples 个值
    【3】max_samples > max_len:read操作失败,返回PRECONDITION_NOT_MET
  • 返回的data_values和sample_info集合有些元素是向DataReader loan的。Data不用了的话,需要用return_loan 还回借用的元素,还回之后集合max_len=0 和 owns=FALSE.
  • app可以通过调用own来哦按断是否需要return_loan
  • 为避免内存泄漏,data_values和sample_info集合不允许更改own = FALSE的集合的长度,也不能删除
  • 在输出中,data_values和sample_info集合长度一样,且一一对应
  1. take:收集来自 DataReader的数据和SampleInfo。会返回一个list的sample或单一sample,这些操作和read一样。但是take会将sample进行移除,之后的DataReader不会再能read和take

  2. read_w_condition :通过read访问与ReadCondition中制定的条件相匹配的sample。

  3. take_w_condition

  4. read_next_sample:从DataReader复制下一个没访问过的数据,还会复制相应的SampleInfo。当max_len=1, the sample_states=NOT_READ, the view_states=ANY_VIEW_STATE, instance_states=ANY_INSTANCE_STATE时,该操作和read一样

  5. take_next_sample

  6. read_instance:拿到DataReader的DataValues,所有的sample都属于一个handle。Data集合包含的所有sample都属于一个instance。能够使用sampleInfo里面的instance_handle == a_handle区分它们。

  7. take_instance

  8. read_next_instance:这个操作用于应用程序驱动的迭代,从previous_handle= =HANDLE_NIL开始,检查返回的样本,使用在SampleInfo中返回的 instance_handle 作为previous_handle参数的值来进行下一次调用read_next_instance,直到read_next_instance的返回值是NO_DATA

  9. take_next_instance

  10. read_next_instance_w_condition

  11. return_loan:实现 read 和 take从DataReader给应用程序 loan buffers的操作,以这种方式实现零拷贝,DataReader保证Data和SampleInfo的信息不被修改。app不能无限期保留buffer,return_loan操作的使用只有在read 和 take操作调用buffer借给app时才有用。

  12. wait_for_historical_data:只适用于QoS为 non-VOLATILE PERSISTENCE 的DataReader。调用阻塞线程,直到接收到所有History数据,或者max_wait超时

猜你喜欢

转载自blog.csdn.net/weixin_42299076/article/details/129704538