Modern C++: Migration path / interacting with traditional C++ API

8 posts / 0 new
Last post
Offline
Last seen: 4 years 11 months ago
Joined: 10/01/2015
Posts: 17
Modern C++: Migration path / interacting with traditional C++ API

I have a project that that currently uses the traditional C++ api. I would like any new code written to use the modern API, but I do not want to rewrite everything at once.

I'm thinking something like an API to get a DDSDomainParticipant reference from a dds::domain::DomainParticipant (or vice versa). Same thing at the Publisher/Subscriber level.

Keywords:
Offline
Last seen: 2 months 1 week ago
Joined: 04/02/2013
Posts: 194

Hi,

Unfortunately you can't mix the modern and traditional C++ APIs in the same .cpp file—the code won't compile.

You can mix the modern C++ and C APIs, or you can use the C++ APIs in different object files as long the same .cpp file doesn't include the headers of both APIs.

This is a technical restriction due to the way certain common C headers are implemented.

Alex

 

Offline
Last seen: 4 years 11 months ago
Joined: 10/01/2015
Posts: 17

Thanks.

Say I have two translation units in a single executable, each using the different C++ API's, but same domain id. Will they share resources internally (network ports, memory, etc), or will it be like having 2 completely separate domain participants running?

If I create a domain participant with the modern c++ api, then later (from a different TR/cpp) call lookup_participant (from the old c++ api), will it find the existing one?

Same question for the various lookup_[publisher|subscriber] functions.

Offline
Last seen: 2 months 1 week ago
Joined: 04/02/2013
Posts: 194

I have put together a little example where you can reuse the Traditional C++ entities in the Modern C++ code. To do that I had to use an internal function to obtain the DomainParticipant. The find() function won't work directly for the DomainParticipant, because the APIs use different DomainParticipantFactories so they don't see each other participants. The Modern C++ API uses the C factory under the hood, but the Traditional API has its own factory. The trick is to pass the C participant from one to the other. But the good news is that once you get the participant, the other find() functions will work (publisher, writer, etc).

I'm attaching the example with the following files:

App.cxx -- The executable that ties together both APIs
Foo_publisher.cxx -- The traditional C++ code
Foo_publisher.h -- The public header for the traditional C++ code
Foo_publisher_new.cxx -- The modern C++ code
Foo_publisher_new.hpp -- and its header

In short, Foo_publisher.cxx creates a participant and returns the C pointer. App.cxx gets that pointer and passes it to Foo_publisher_new.cxx, which does the magic to obtain a modern C++ participant and reuse it.

This example doesn't deal with the destruction of the participant (it leaks memory), but that should be easy to implement by having App.cxx call a cleanup function in Foo_publisher.cxx.

I hope this helps with the transition to modern C++.

File Attachments: 
Offline
Last seen: 4 years 11 months ago
Joined: 10/01/2015
Posts: 17

Thanks, this looks like a good start. It should make the transition to the new API much smoother for me.

Offline
Last seen: 4 years 11 months ago
Joined: 10/01/2015
Posts: 17

Is it possible to go the other way? Start by creating a modern-api participant and get an old-api participant from it?

Offline
Last seen: 2 months 1 week ago
Joined: 04/02/2013
Posts: 194

You can create the participant in the modern C++ API and then use it in the C API, but I don't see a way to use it in the traditional C++ API.

Offline
Last seen: 4 years 11 months ago
Joined: 10/01/2015
Posts: 17

I've finally got to trying this out with real code and ran into an issue.

My traditional-c++ domain participant has a listener attached.  When events from the modern api would cause that listener to be executied, the app crashes.  It looks like a null pointer in the RTI library.

Attached test case and stack trace.

 

(lldb) bt * thread #2, stop reason = EXC_BAD_ACCESS (code=1, address=0x50) * frame #0: 0x00000001000bc6a3 test_publisher`::DDSDomainParticipantListener_forward_onPublicationMatched(listener_data=0x0000000101707380, cDataWriter=0x00000001038773f0, status=0x000070000aaf2518) at DomainParticipantListener.cxx:286 frame #1: 0x0000000100276107 test_publisher`DDS_DomainParticipantListener_forward_onPublicationMatched(listener=0x0000000100dd30c0, writer=0x0000000103877160, status=0x000070000aaf25b8, worker=0x0000000101413ef0) at DomainParticipantListener.c:376 frame #2: 0x000000010088f479 test_publisher`PRESPsService_changeWriterLivelinessStatus(me=0x0000000105800000, rwWriter=0x0000000103876a10, remoteReaderGuid=0x000000010388bf58, isReliable=0, reason=PRES_PS_SERVICE_LIVELINESS_CHANGED_REASON_NEW_ACTIVE, worker=0x0000000101413ef0) at PsServiceLinkStatus.c:164 frame #3: 0x00000001008702b3 test_publisher`PRESPsService_linkToLocalWriter(me=0x0000000105800000, remoteReaderWRPt=0x00000001038028c8, worker=0x0000000101413ef0) at PsServiceLink.c:4212 frame #4: 0x00000001007fb024 test_publisher`PRESPsService_onLinkToLocalEndpointEvent(listener=0x0000000105800810, newTime=0x000070000aaf3d48, newSnooze=0x000070000aaf3d40, now=0x000070000aaf3d60, time=0x00000001038028b0, snooze=0x00000001038028b8, storage=0x00000001038028c8, worker=0x0000000101413ef0) at PsServiceEvent.c:166 frame #5: 0x0000000100ab0861 test_publisher`RTIEventActiveGeneratorThread_loop(param=0x00000001014104a0) at ActiveGenerator.c:214 frame #6: 0x0000000100c59808 test_publisher`RTIOsapiThreadChild_onSpawned(param=0x00000001014124f0) at Thread.c:1266 frame #7: 0x00007fff7831c6c1 libsystem_pthread.dylib`_pthread_body + 340 frame #8: 0x00007fff7831c56d libsystem_pthread.dylib`_pthread_start + 377 frame #9: 0x00007fff7831bc5d libsystem_pthread.dylib`thread_start + 13

File Attachments: