eclipse-iceoryx / iceoryx

Eclipse iceoryx™ - true zero-copy inter-process-communication
https://iceoryx.io
Apache License 2.0
1.6k stars 373 forks source link

Sending/Receiving Complex Data Structures #517

Closed Indra5196 closed 3 years ago

Indra5196 commented 3 years ago

Required information

Operating system: Ubuntu 18.04 LTS

Compiler version: GCC 7.5.0

Iceoryx versioin: 0.90.0.0

Observed result or behaviour: I created a structure which is as follows: struct MyStruct { std::vector charArray; };

I am using this in place of "RadarObject" struct in the untyped example

Publisher code: auto result = untypedPublisher.loan(sizeof(MyStruct)); if (!result.has_error()) { auto& sample = result.value(); // In the untyped API, the returned sample is a void pointer, therefore the data must be constructed // in place auto object = static_cast<MyStruct>(sample.get()); object = MyStruct(); object->charArray.push_back('A'); sample.publish(); }

Subscriber code: if (untypedSubscriber.getSubscriptionState() == iox::SubscribeState::SUBSCRIBED) { untypedSubscriber.take() .and_then([](iox::popo::Sample& sample) { auto object = static_cast<const MyStruct*>(sample.get()); std::cout << "Got value: " << object->charArray.at(0) << std::endl; }) .if_empty([] { std::cout << std::endl; }) .or_else( { std::cout << "Error receiving chunk." << std::endl; }); } else { std::cout << "Not subscribed!" << std::endl; }

When I run my application, publisher crashes.

I have tried something similar with Iceoryx version 0.17.0.2, but I was receiving blanks at the receiver

I mainly want to know whether we can actually transfer complex data types with Iceoryx or we need to follow some workaround?

Expected result or behaviour: Data transfers successfully

elfenpiff commented 3 years ago

@Indra5196 to implement a zero copy data transfer we us a shared memory approach. This requires that every data structure needs to be stored in there and that they do not use the heap. An std::vector uses the heap to acquire memory to store the elements in there. This leads to the following problem.

  1. Your application sends some data
  2. The receiver receives a pointer to the data in the shared memory (zero copy)
  3. When the receiver dereferences the data it accesses the std::vector which then would like to access his heap memory to read the elements which are stored in the process space of your sender application and this causes a segmentation fault since you as a stranger process are not allowed to access memory of another process. This is only with shared memory allowed.

Solution: Update your structure so that it uses our cxx::vector implementation and you are good to go.

struct MyStruct {
  cxx::vector<char, 1337> charArray;
};

It can be used like a normal vector but it does not use the heap under the hood. This is why you have to provide the maximum cxx::vector capacity at compile time - in this case it is 1337.

I mainly want to know whether we can actually transfer complex data types with Iceoryx or we need to follow some workaround?

You can transfer every data type which does not use the heap. Those are for instance c style arrays, all the POD types (int, float, char ...), std::array and some more. If you encounter this issue again you could take a look at: https://github.com/eclipse-iceoryx/iceoryx/tree/master/iceoryx_utils/include/iceoryx_utils/cxx where you find data types which are not using the heap and can be used as an alternative for std::vector for instance. There usage should be similar to the stl containers.

For std::map or and std::set we do not have an alternative at the moment but if the need arises on your end please create an issue.

Indra5196 commented 3 years ago

Thank you very much. That helped a lot!

mossmaurice commented 3 years ago

Added an item in #482 that we need to document the limitations of what can be transmitted via shared memory. Closing this issue and we can continue the wishlist of data types and possible solutions in #594