Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interprocess communication: passing C-style structs vs C++-objects

Warning/Disclaimer:

This question contains heresay, but I could not find the answers to the claims stated below, in my little research done in the last half an hour or so. I am just curious if someone here already knows about this.

This question has no code. Just technical queries.

Background:

I have a legacy application, which uses C-style structs passed between processes for interprocess communication. And this works quite well and has been working for many many years, long before even I was on this planet :P.

I was supposed to write a new process that would become part of this application. Unwittingly, I wrote it in C++, assuming whaterver IPC, we are using could handle this. Unfortunately, then I found out (from colleagues) that the existing infrastructure can only pass C-style structs.

'Unverified' claims/statements:

In addition,one of the colleagues listed the following reasons why C++ was a bad choice in this case.

  1. C++ objects have vtables. C-style structs are just variables and values. Therefore C-style structs can be passed around processes, while C++ objects cannot be.

  2. With C-style structs we can embed information like size of the struct, so that both sides know what to expect and what to send, but for C++ objects this is not possible since 'the size of the vtable could vary'.

  3. 'If we change compilers, then it is even worse. We would have even more permutations to deal with for the case of C++ objects.'

Investigating the claims:

Needless to say, this colleague has a little bias for C, but he is much more experienced than me and probably knows what he is talking about. I am language-agnostic. But this immediately got me thinking. How can it be that we cannot do interprocess communication with C++? I googled and the first hits were invariably from stackoverflow, like this one:

Inter-Process Communication Recommendation

And I looked up on the different methods of IPC listed here. https://en.wikipedia.org/wiki/Inter-process_communication#Approaches

I mean, I followed up on each of those methods in the list like pipes or shared memory, etc and the only caveat that everyone keeps on pointing out, is, that pointers (duh! of course) cannot be passed like this and some issues with synchronization could creep up - je nachdem.

BUT nowhere could I find something that could refute or corroborate his 'claims'. (Of course, I could continue on digging for the rest of the day. :P)

Questions:

  1. Are his three claims really so or was it just FUD? Considering that, all that I have in those objects that I wanted wanted to pass around are also only, POD variables and some STL containers like std::vector and std::pair and their values (no pointers or anything), and the getters for those variables. There are no virtual functions except the virtual destructor, which exists since I inherited all the messages from one base message class, since at that time, I was thinking that there might be some common base functionality. (I could get rid of this base class quite easily now, since there is nothing really common there till now! Thankfully for some reason I kept the parsing and formatting of messages in a separate class. Luck or foresight? :D )

  2. It also actually makes me wonder, how does the compiler know when a struct is a C-style struct since we are using the g++ compiler for the whole project anyways? Is it the use of the 'virtual' keyword?

  3. I am not asking for a solution for my case. I can wrap the results from those objects into structs and pass them on through the IPC or I could get rid of base class and virtual destructor as stated in 'my' point 1 above.

Boost or any C++11 stuff or any library that handles this is not desired. Any suggestions in this regard are tangential to the question at hand.

(p.s. Now that I posted and re-read what I posted, I want to nip the thought in the bud that might be creeping up in any reader's head who reads this, that ... I am asking this for my knowledge, and not for arguing with that colleague. Skepticism is good, but would be nice for the community if we all assumed others to have good intentions.:) )

like image 666
Duck Dodgers Avatar asked Mar 04 '23 20:03

Duck Dodgers


1 Answers

only caveat that everyone keeps on pointing out, is, that pointers (duh! of course) cannot be passed like this

Pointer values (as well as other references to memory and resources) are indeed meaningless across processes. This is obviously a consequence of virtual memory.

Another caveat is while C standard specifies exact (platform specific) memory layout for structs, C++ standard doesn't guarantee a particular memory layout for classes in general. One process doesn't necessarily agree with another process on the amount of padding between members for example - even within the same system. C++ only guarantees memory layout for standard layout types - and this guaranteed layout matches with C structs.


... and some STL containers like std::vector ... (no pointers or anything)

All standard containers except std::array use pointers internally. They have to because their size is dynamic, and therefore must allocate the data structures dynamically. Also, none of those are standard layout classes. Furthermore, the class definitions of one standard library implementation are not guaranteed to match another implementation and two processes can use different standard libraries - this is not at all uncommon on Linux where some processes might use libstdc++ (from GNU) while others might use libc++ (from Clang).

There are no virtual functions except the virtual destructor

In other words: There is at least one virtual function (the destructor), and therefore there is a pointer to a vtable. And also no guaranteed memory layout because classes with virtual functions are never standard layout classes.


So to answer the questions:

  1. Mostly no FUD, although some claims are technically a bit inaccurate:

    1. C++ objects may have vtables; not all of them do. C structures can have pointers, so not all C structures can be shared either. Some C++ objects can be shared accross processes. Specifically, standard layout classes can be shared (assuming there are no pointers).
    2. Objects with vtables cannot be shared indeed.
    3. Standard layout classes have a guaranteed memory layout. Changing the compiler is not a problem as long as you restrict yourself to standard layout classes. Trying to share other classes might appear work if you're unlucky, but you'll probably face problems when you start mixing compilers.
  2. The C++ stadard defines the exact conditions where a class is standard layout. All C struct definitions are standard layout classes in C++. The compiler knows those rules.

  3. This is not a question.


Conclusion: You can use C++ for IPC, but you're limited to standard layout classes in that interface. This excludes you from many C++ features such as virtual functions, access specifiers etc. But not all: You can still have member functions for example.

Do note however, that using C++ features may cause the inter process interface to only work with C++. Many languages can interface with C, but hardly any can interface with C++.

Furthermore: If your "interprocess" communication goes beyond the boundaries of the system - across network that is - even a C structure or standard layout class is not a good representation. In that case you need serialisation.

like image 53
eerorika Avatar answered Mar 07 '23 11:03

eerorika