Create A P2P Distributed Application In Under 35 Lines Of C++11 Code! 7

If I had to give you one reason why C++ is king (and this isn’t changing anytime soon) it would be this: C++ lets you create very powerful abstractions with zero or minimal runtime impact. Few languages can offer both.When designing your API, it’s critical that you take advantage of what the language has to offer – leveraging its strengths to enhance, among other things, its usability.

C++ is much more than C with classes, but we found that our existing RTI Connext DDS C++ API lacked this spirit. We didn’t take full advantage of its strengths, partly because we wanted to support old compilers. As a result, the API didn’t meet the needs of some of our users. Fortunately that’s going to change (very) soon!

I’m really excited to say that our new C++ API is receiving the attention it deserves. The new API, based on the OMG DDS C++ PSM includes what customers like you want to see in a modern C++ API. Designed with generic programming at its heart, the new C++ API is easy to use, STL-friendly, and ready for C++11.

To prove it, I’m going to show you how you can write your peer-to-peer distributed Hello World applications (publisher and subscriber) in under 35 lines of code, because fewer lines that do more mean less code to maintain and fewer chances to write bugs.

void publisher()
{
    DomainParticipant participant (0);
    Topic<StringTopicType> topic (participant, "Hello World Topic");
    DataWriter<StringTopicType> writer(Publisher(participant), topic);

    writer.write("Hello, World!");
}

void subscriber()
{
    DomainParticipant participant (0);
    Topic<StringTopicType> topic (participant, "Hello World Topic");
    DataReader<StringTopicType> reader (Subscriber(participant), topic);

    ReadCondition read_condition (
        reader,
        DataState::any_data(),
        [reader]()
        {
            LoanedSamples<StringTopicType> samples = reader.take();
            std::copy(
                rti::sub::valid_samples(samples.begin()),
                rti::sub::valid_samples(samples.end()),
                std::ostream_iterator<const StringTopicType&>(std::cout, "\n"));
        }
    );

    WaitSet waitset;
    waitset += read_condition;

    while (1) {
        waitset.dispatch(Duration(20));
    }
}

If you’re familiar with DDS, you probably know exactly what is going on. If you don’t, you just need to know briefly what these entities mean in the world of DDS:

  • A participant is the entity that lets you join a domain, which is a logical partition of the world identified by an ID.
  • A topic names what you are interested in (subscription) or what you know about (publication). A topic has a type associated to it.
  • A DataReader lets you receive data from a topic and a DataWriter lets you send data about a topic.

RTI Connext DDS takes care of matching subscribers and publishers of a topic and delivering data to the interested parties efficiently. Using WaitSets and Conditions is one of the patterns you can use to get notified about new data.

Basic DDS entities

DDS entities in our Hello World example

You can compare this code with a similar example in the current Connext DDS C++ API: publisher and subscriber.

You might first notice that we don’t need a single line of code for error checking or cleanup. The API throws exceptions in case of errors. You only need to handle exceptions if you have something useful to do—otherwise just let them propagate. Smart pointers manage entities such as the DomainParticipant or the DataReader and destructors take care of the cleanup for you. Even the LoanedSamples object, encapsulating data owned by the inner layers of the middleware, will return the loan in its destructor.

As I said before, generic programming dominates the API. In fact, we could have written this example for a generic data type T and barely changed anything else. If T is not a valid DDS type, you’ll find out at compile time, because the types you can use define the compile-time constant dds::topic::is_topic_type<T>::value to 1. No surprises at run-time!

The use of iterators lets us write pretty cool, succinct code, such as the call to std::copy—free of loops or conditions.

std::copy(
    rti::sub::valid_samples(samples.begin()),
    rti::sub::valid_samples(samples.end()),
    std::ostream_iterator<const StringTopicType&>(std::cout, "\n"));

That code is equivalent to:

for (rti::sub::SampleRef<StringTopicType> sample : samples) {
    if (sample.info().valid()) {
        std::cout << sample.data() << "\n";
    }
}

First, iterators let us feed our data into any generic algorithm. By using an iterator adapter (valid_samples) we iterate only through samples that contain valid data. Finally, since we tell the compiler how to automatically get the data (T) from a SampleRef<T>, you don’t need to do it yourself.

Another new and interesting pattern in the API is the association of WaitSet Conditions and their handlers. The operation WaitSet::dispatch() directly calls the handlers of the active conditions—your application no longer needs to make that association as it would in the current API.

With compiler support, you can write your function as a lambda right where it matters.

As you can see, a lot has changed to make your code shorter, easier to maintain and use, and more robust. The best part is that none of these abstractions make the application run any slower.

This was just a small sample of the new C++ API. Please leave your comments and questions here or in the RTI Community. If you want to access to a preview version, contact us at cpp_psm@rti.com. UPDATE: The Modern C++ API is already available with RTI Connext 5.2

One Admin Console To Debug Them All! Reply

ac-blog-1

Better DDS Debugging with Admin Console

How can you debug a program when data is not flowing? It’s difficult to even diagnose a data flow issues since Quality of Service (QoS) can vary from one application to another. The problem can be compounded by the sheer scale of a system, as well as the integration of subsystems in a heterogeneous environment.

To ease debugging, the RTI Admin Console in Connext DDS 5.1 has added real-time match analyses. Each time a new DataWriter or DataReader is discovered, Admin Console evaluates its QoS as it relates to the other DataWriters and DataReaders associated with that topic. This evaluation is updated as the system changes.

ac-blog-2

Let’s say a specific DataReader deadline is compatible with a specific DataWriter. Then assume an application changes the deadline of that DataReader to make it incompatible with the DataWriter. Admin Console is notified of the updated QoS (through Discovery) and updates the match status.

So, what does it look like? Well, let’s walk through the user interface elements. First, the Physical View shows that the System, Host (balancerock in this case), and processes are in an error state.

The DDS Logical View also gets in on the act by showing the Topic which has the error. The DDS Logical View provides a DDS-centric view of the system by putting Topics under their respective Domains.

ac-blog-3

We click on the ‘Square’ Topic to bring up the Topic Editor. While there are two DataWriters, only one of them is mismatched. The DataReader is shown as ‘Partially matched’ because it matches one DataWriter but not the other.

ac-blog-4

We select the mismatched DataWriter and turn our attention to the ‘Match Analyses’ tab to discover the reasons for the problem.

ac-blog-5

It seems there are two problems; the Ownership and the Deadline QoSes are mismatched.

Did you notice that the QoS policies in the first column are formatted like hyperlinks? That’s because they are hyperlinks. If you click on the Ownership hyperlink, Admin Console shows you the compatibility documentation for the Ownership QoS policy. The other hyperlink points to the Deadline QoS policy.

Code Generator 2: Generate Code Faster 1

Are you tired of waiting for all your code to be generated? Would you like to customize the generated output? Code Generator 2 is your solution. This new code generator is already available in your RTI Connext DDS 5.1.0 installation as an Early Access Release (EAR).

Code Generator 2 is written completely in Java and uses Apache Velocity (VLT) templates to define the generated output. This allows you to customize the generated code for different languages by modifying those templates. Check the predefined set of variables available in RTI_rtiddsgen_template_variables.xlsx, located in the Code Generator 2 documentation.

This new design also improves performance compared to the current code generator. The VLT templates are parsed faster than the XSLT ones (used by the current code generator). When generating code for a large IDL, Code Generator 2 is up to 10 times faster than the current code generator.

If you want to invoke the code generator multiples times with different parameters or IDL files, Code Generator 2 provides a server mode that further improves its performance. When used in server mode, Code Generator 2 runs as a native executable that connects through TCP with a server instance of the code generator. The server instance is initiated automatically the first time that the code generator is invoked and it is automatically stopped after an inactivity period. As a result, the JVM is only loaded once when the server is started, the VLT templates are compiled once and the following invocations to Code Generator 2 are resolved faster.

BoostingPerformance2.jpg

Do you want to try Code Generator 2? Just run the rtiddsgen2 or the rtiddsgen2_server (for running in server mode) scripts with the usual parameters. If you need more information about supported and new features available in Code Generator 2, check out its Getting Started Guide.