In this recipe, we will start with the source code that uses regular files for IPC. We will modify it to use an IPC mechanism called named pipes:
- Copy the contents of the ipc1 directory into a new directory called ipc2.
- Open the ipc1.cpp file and add two more include instance after #include <unistd.h>:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
- Modify the Write method of the Writer class by adding one more line:
void Write(const T& data) {
out.write(reinterpret_cast<const char*>(&data), sizeof(T));
out.flush();
}
- Modifications in the Reader class are more substantial. Both the constructor and the Read method are affected:
template<class T>
class Reader {
private:
std::ifstream in;
public:
Reader(std::string& name):
in(name, std::ofstream::binary) {}
T Read() {
T data;
in.read(reinterpret_cast<char*>(&data), sizeof(data));
if (!in) {
throw std::runtime_error("Failed to read a message");
}
return data;
}
};
- Add a small change to the DoWrites function. The only difference is we add a 10 millisecond delay after sending each message:
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);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
- Finally, modify our main function to create a named pipe instead of a regular file:
int main(int argc, char** argv) {
int ret = mkfifo(kSharedFile.c_str(), 0600);
if (!ret) {
throw std::runtime_error("Failed to create named pipe");
}
if (fork()) {
DoWrites();
} else {
DoReads();
}
}
You can now build and run the application.