3.4.8. Accessing received data

The application can access and consume the data values received on the DataReader by reading or taking.

  • Reading is done with the DataReader::read_next_sample() member function. It reads the next, non-previously accessed data value available on the DataReader, and stores it in the provided data buffer.

  • Taking is done with the DataReader::take_next_sample() member function. It reads the next, non-previously accessed data value available on the DataReader, and stores it in the provided data buffer. Additionally, it also removes the value from the DataReader, so it is no longer accessible.

If there is no unread data in the DataReader, both operations will return NO_DATA and nothing is returned.

In addition to the data value, the data access operations also provide a SampleInfo instance with additional information that help interpreting the returned data value, like the originating DataWriter or the publication time stamp. Please, refer to the SampleInfo section for an extensive description of its contents.

3.4.8.1. Accessing data on callbacks

When the DataReader new data values from any matching DataWriter, it informs the application through two Listener callbacks:

These callbacks can be used to retrieve the newly arrived data, as in the following example.

class CustomizedDataReaderListener : public DataReaderListener
{

public:

    CustomizedDataReaderListener()
    : DataReaderListener()
    {
    }

    virtual ~CustomizedDataReaderListener()
    {
    }

    virtual void on_data_available(
            DataReader* reader)
    {
        // Create a data and SampleInfo instance
        void* data = reader->type().create_data();
        SampleInfo info;

        // Keep taking data until there is nothing to take
        while (reader->take_next_sample(&data, &info) == ReturnCode_t::RETCODE_OK)
        {
            if (info.instance_state == ALIVE)
            {
                // Do something with the data
                std::cout << "Received new data value for topic "
                          << reader->get_topicdescription()->get_name()
                          << std::endl;
            }
            else
            {
                std::cout << "Remote writer for topic "
                          << reader->get_topicdescription()->get_name()
                          << " is dead" << std::endl;
            }
        }

        // The data instance can be reused to retrieve new values,
        // but delete it at the end to avoid leaks
        reader->type().delete_data(data);
    }
};

Note

If several new data changes are received at once, the callbacks may be triggered just once, instead of once per change. The application must keep reading or taking until no new changes are available.

3.4.8.2. Accessing data with a waiting thread

Instead of relying on the Listener to try and get new data values, the application can also dedicate a thread to wait until any new data is available on the DataReader. This can be done with the wait_for_unread_message() member function, that blocks until a new data sample is available or the given timeout expires. If no new data was available after the timeout expired, it will return with value false. This function returning with value true means there is new data available on the DataReaderListener ready for the application to retrieve.

// Create a DataReader
DataReader* data_reader =
        subscriber->create_datareader(topic, DATAREADER_QOS_DEFAULT);
if (nullptr != data_reader)
{
    // Error
    return;
}

// Create a data and SampleInfo instance
void* data = data_reader->type().create_data();
SampleInfo info;

//Define a timeout of 5 seconds
eprosima::fastrtps::Duration_t timeout (5,0);

// Loop reading data as it arrives
// This will make the current threat to be dedicated exclusively to
// waiting and reading data until the remote DataWriter dies
while (true)
{
    if (data_reader->wait_for_unread_message(timeout))
    {
        if (data_reader->take_next_sample(&data, &info) == ReturnCode_t::RETCODE_OK)
        {
            if (info.instance_state == ALIVE)
            {
                // Do something with the data
                std::cout << "Received new data value for topic "
                          << topic->get_name()
                          << std::endl;
            }
            else
            {
                // If the remote writer is not alive, we exit the reading loop
                std::cout << "Remote writer for topic "
                          << topic->get_name()
                          << " is dead" << std::endl;
                break;
            }
        }
    }
    else
    {
        std::cout << "No data this time" << std::endl;
    }
}

// The data instance can be reused to retrieve new values,
// but delete it at the end to avoid leaks
data_reader->type().delete_data(data);