In this recipe, we will create a sample application that creates two processes. One process generates data while another reads the data and prints it to the console:
- In your working directory (~/test), create a subdirectory called ipc1.
- Use your favorite text editor to create an ipc1.cpp file in the ipc1 subdirectory.
- We are going to define two templated classes to organize our data exchange. The first class, Writer, is used to write data into a file. Let's put its definition in the ipc1.cpp file:
#include <fstream>
#include <iostream>
#include <thread>
#include <vector>
#include <unistd.h>
std::string kSharedFile = "/tmp/test.bin";
template<class T>
class Writer {
private:
std::ofstream out;
public:
Writer(std::string& name):
out(name, std::ofstream::binary) {}
void Write(const T& data) {
out.write(reinterpret_cast<const char*>(&data), sizeof(T));
}
};
- This is followed by the definition of the Reader class, which is responsible for reading data from a file:
template<class T>
class Reader {
private:
std::ifstream in;
public:
Reader(std::string& name) {
for(int count=10; count && !in.is_open(); count--) {
in.open(name, std::ifstream::binary);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
T Read() {
int count = 10;
for (;count && in.eof(); count--) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
T data;
in.read(reinterpret_cast<char*>(&data), sizeof(data));
if (!in) {
throw std::runtime_error("Failed to read a message");
}
return data;
}
};
- Next, we define the data type that we will use for our data:
struct Message {
int x, y;
};
std::ostream& operator<<(std::ostream& o, const Message& m) {
o << "(x=" << m.x << ", y=" << m.y << ")";
}
- To wrap everything together, we define the DoWrites and DoReads functions, as well as the main function that invokes them:
void DoWrites() {
std::vector<Message> messages {{1, 0}, {0, 1}, {1, 1}, {0, 0}};
Writer<Message> writer(kSharedFile);
for (const auto& m : messages) {
std::cout << "Write " << m << std::endl;
writer.Write(m);
}
}
void DoReads() {
Reader<Message> reader(kSharedFile);
try {
while(true) {
std::cout << "Read " << reader.Read() << std::endl;
}
} catch (const std::runtime_error& e) {
std::cout << e.what() << std::endl;
}
}
int main(int argc, char** argv) {
if (fork()) {
DoWrites();
} else {
DoReads();
}
}
- Finally, create a CMakeLists.txt file containing the build rules for our program:
cmake_minimum_required(VERSION 3.5.1)
project(ipc1)
add_executable(ipc1 ipc1.cpp)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
SET(CMAKE_CXX_FLAGS "--std=c++11")
set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++)
You can now build and run the application.