1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
# Single process
## Introduction
This example demonstrates how iceoryx can be used in a single process for
inter-thread communication. This is for instance helpful if you would like
to establish a simple communication API in a 3D engine with a multitude of
threads that are interacting without starting RouDi every time separately.
## Run singleprocess
[](https://asciinema.org/a/407439)
The first lines until `RouDi is ready for clients` are coming from the RouDi
startup in which the shared memory management segment and user data segment are
created.
Afterward, the publisher and subscriber thread are started and are beginning to
transmit and receive data.
## Code Walkthrough
### Creating a Single Process RouDi, Publisher and Subscriber
1. We start by setting the log level to error since we do not want to see all the
debug messages.
<!--[geoffrey][iceoryx_examples/singleprocess/single_process.cpp][log level]-->
```cpp
iox::log::LogManager::GetLogManager().SetDefaultLogLevel(iox::log::LogLevel::kError);
```
2. To start RouDi we have to create a configuration for him. We are choosing the
default config. Additionally, RouDi needs some other components like a memory
management unit which handles how the memory is created in which the transmission
data is stored. The `IceOryxRouDiComponents` class is handling them for us
<!--[geoffrey][iceoryx_examples/singleprocess/single_process.cpp][roudi config]-->
```cpp
iox::RouDiConfig_t defaultRouDiConfig = iox::RouDiConfig_t().setDefaults();
iox::roudi::IceOryxRouDiComponents roudiComponents(defaultRouDiConfig);
```
3. We are starting RouDi, provide the required components and
disable monitoring. The last bool parameter `TERMINATE_APP_IN_ROUDI_DTOR_FLAG`
states that RouDi does not
terminate all registered processes when RouDi goes out of scope. If we would set it
to `true`, our application would self terminate in the destructor of `roudi`.
<!--[geoffrey][iceoryx_examples/singleprocess/single_process.cpp][roudi]-->
```cpp
constexpr bool TERMINATE_APP_IN_ROUDI_DTOR_FLAG = false;
iox::roudi::RouDi roudi(
roudiComponents.rouDiMemoryManager,
roudiComponents.portManager,
iox::roudi::RouDi::RoudiStartupParameters{iox::roudi::MonitoringMode::OFF, TERMINATE_APP_IN_ROUDI_DTOR_FLAG});
```
4. Here comes a key difference to an inter-process application. If you would like
to communicate within one process, you have to use `PoshRuntimeSingleProcess`.
You can create only one runtime at a time!
<!--[geoffrey][iceoryx_examples/singleprocess/single_process.cpp][runtime]-->
```cpp
iox::runtime::PoshRuntimeSingleProcess runtime("singleProcessDemo");
```
5. Now that everything is up and running, we can start the publisher and subscriber
thread and wait until the user terminates the application.
<!--[geoffrey][iceoryx_examples/singleprocess/single_process.cpp][run]-->
```cpp
std::thread publisherThread(publisher), subscriberThread(subscriber);
iox::posix::waitForTerminationRequest();
publisherThread.join();
subscriberThread.join();
std::cout << "Finished" << std::endl;
```
### Implementation of Publisher and Subscriber
Since there are no differences to the inter-process ports you can take a look at the
[icedelivery example](https://github.com/eclipse-iceoryx/iceoryx/tree/v2.0.0/iceoryx_examples/icedelivery)
for a detailed documentation. We only provide here a short overview.
#### Publisher
We create a typed publisher with the following service description
(Service = `Single`, Instance = `Process`, Event = `Demo`) and a `historyCapacity`
of 10.
<!--[geoffrey][iceoryx_examples/singleprocess/single_process.cpp][publisher]-->
```cpp
iox::popo::PublisherOptions publisherOptions;
publisherOptions.historyCapacity = 10U;
iox::popo::Publisher<TransmissionData_t> publisher({"Single", "Process", "Demo"}, publisherOptions);
```
After that, we are sending numbers in ascending order with a 100ms interval in a `while` loop.
<!--[geoffrey][iceoryx_examples/singleprocess/single_process.cpp][send]-->
```cpp
uint64_t counter{0};
constexpr const char GREEN_RIGHT_ARROW[] = "\033[32m->\033[m ";
while (!iox::posix::hasTerminationRequested())
{
publisher.loan().and_then([&](auto& sample) {
sample->counter = counter++;
consoleOutput("Sending ", GREEN_RIGHT_ARROW, sample->counter);
sample.publish();
});
std::this_thread::sleep_for(CYCLE_TIME);
}
```
#### Subscriber
We create a subscriber port with the same service description, a `queueCapacity`
of 10 and request to get the last 5 samples when we connect (`historyRequest`).
<!--[geoffrey][iceoryx_examples/singleprocess/single_process.cpp][subscriber]-->
```cpp
iox::popo::SubscriberOptions options;
options.queueCapacity = 10U;
options.historyRequest = 5U;
iox::popo::Subscriber<TransmissionData_t> subscriber({"Single", "Process", "Demo"}, options);
```
Now we can receive the data in a while loop when our `SubscribeState` is `SUBSCRIBED`
until someone terminates the application.
<!--[geoffrey][iceoryx_examples/singleprocess/single_process.cpp][receive]-->
```cpp
constexpr const char ORANGE_LEFT_ARROW[] = "\033[33m<-\033[m ";
while (!iox::posix::hasTerminationRequested())
{
if (iox::SubscribeState::SUBSCRIBED == subscriber.getSubscriptionState())
{
bool hasMoreSamples{true};
do
{
subscriber.take()
.and_then([&](auto& sample) { consoleOutput("Receiving ", ORANGE_LEFT_ARROW, sample->counter); })
.or_else([&](auto& result) {
hasMoreSamples = false;
if (result != iox::popo::ChunkReceiveResult::NO_CHUNK_AVAILABLE)
{
std::cout << "Error receiving chunk." << std::endl;
}
});
} while (hasMoreSamples);
}
std::this_thread::sleep_for(CYCLE_TIME);
}
```
<center>
[Check out singleprocess on GitHub :fontawesome-brands-github:](https://github.com/eclipse-iceoryx/iceoryx/tree/v2.0.0/iceoryx_examples/singleprocess){ .md-button }
</center>
|