File: README.md

package info (click to toggle)
iceoryx 2.0.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 11,260 kB
  • sloc: cpp: 94,127; ansic: 1,443; sh: 1,436; python: 1,377; xml: 80; makefile: 61
file content (165 lines) | stat: -rw-r--r-- 6,157 bytes parent folder | download | duplicates (3)
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

[![asciicast](https://asciinema.org/a/407439.svg)](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>