Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <exception>
- #include <iostream>
- #include <set>
- #include <stdexcept>
- #include <string>
- #include <vector>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <fcntl.h>
- #include <unistd.h>
- auto constexpr max_size = 50;
- struct Pipe {
- std::string name;
- int descriptor;
- FILE* handle;
- Pipe(std::string const& n, int fd, FILE* fh) : name{n}, descriptor{fd}, handle{fh} {}
- };
- struct Message {
- enum class Type { Request, Response, Exit };
- static Message read(Pipe const& pipe) {
- char buffer[sizeof(Message)] = { 0 };
- auto v = ::read(pipe.descriptor, buffer, sizeof(Message));
- if(v == -1 || v != sizeof(Message)) {
- throw std::runtime_error("Error while reading message from " + pipe.name +
- " read bytes: " + std::to_string(v));
- }
- Message rv;
- memcpy(&rv, buffer, sizeof(Message));
- return rv;
- }
- static void write(Pipe& pipe, Message& message) {
- char buffer[sizeof(Message)] = { 0 };
- memcpy(buffer, &message, sizeof(Message));
- auto v = ::write(pipe.descriptor, buffer, sizeof(Message));
- if(v == -1 || v != sizeof(Message)) {
- throw std::runtime_error("Error while writing message to " + pipe.name +
- " written bytes: " + std::to_string(v));
- }
- }
- Type type;
- int process;
- int clock;
- Message(Type t = Type::Request, int p = -1, int c = -1) : type{t}, process{p}, clock{c} {}
- };
- bool operator<(Message const& lhs, Message const& rhs) {
- return lhs.clock < rhs.clock;
- }
- bool operator==(Message const& lhs, Message const& rhs) {
- return lhs.type == rhs.type && lhs.process == rhs.process && lhs.clock == rhs.clock;
- }
- bool operator!=(Message const& lhs, Message const& rhs) { return !(lhs == rhs); }
- namespace std {
- std::string to_string(Message const& message) {
- std::string rv;
- switch(message.type) {
- case Message::Type::Request:
- rv += "Request";
- break;
- case Message::Type::Response:
- rv += "Response";
- break;
- case Message::Type::Exit:
- rv += "Exit";
- break;
- default:
- throw std::runtime_error("Unknown message type");
- }
- rv += "(" + std::to_string(message.process) + ", " + std::to_string(message.clock) + ")";
- return rv;
- }
- }
- std::string process_prefix(int process_no) {
- return "Process " + std::to_string(process_no) + ": ";
- }
- std::vector<std::string> generate_pipes(std::string const& prefix, int count) {
- std::clog << "Generate pipes with prefix " + prefix + " count: " + std::to_string(count) + '\n';
- auto pipe_names = std::vector<std::string>(count);
- for(auto i = 0; i < count; ++i) {
- auto pipe_name = prefix + std::to_string(i);
- unlink(pipe_name.c_str());
- if(mknod(pipe_name.c_str(), S_IFIFO | 00600, 0) == -1) {
- throw std::runtime_error("Unable to create pipe " + pipe_name);
- }
- pipe_names[i] = pipe_name;
- std::clog << "Generated pipe " + pipe_name + '\n';
- }
- return pipe_names;
- }
- std::vector<Pipe> open_pipes(std::vector<std::string> const& pipe_names, int process_no, int count) {
- auto pipes = std::vector<Pipe>();
- auto process_name = process_prefix(process_no);
- for(auto i = 0; i < count; ++i) {
- auto& pipe_name = pipe_names[i];
- std::clog << process_name + "opening pipe " + pipe_name + '\n';
- if(i == process_no) {
- auto fd = open(pipe_name.c_str(), O_RDONLY);
- if(fd == -1) {
- throw std::runtime_error(process_name + "unable to open " + pipe_name + " for reading");
- }
- auto fh = fdopen(fd, "r");
- if(fh == NULL) {
- throw std::runtime_error(process_name + "nable to open file " + pipe_name + " for reading");
- }
- pipes.emplace_back(pipe_name, fd, fh);
- std::clog << process_name + "opened pipe " + pipe_name + " for reading\n";
- }
- else {
- auto fd = open(pipe_name.c_str(), O_WRONLY);
- if(fd == -1) {
- throw std::runtime_error(process_name + "unable to open " + pipe_name + " for writing");
- }
- auto fh = fdopen(fd, "w");
- if(fh == NULL) {
- throw std::runtime_error(process_name + "unable to open file " + pipe_name + " for writing");
- }
- pipes.emplace_back(pipe_name, fd, fh);
- std::clog << process_name + "opened pipe " + pipe_name + " for writing\n";
- }
- }
- return pipes;
- }
- void critical(int process_no) {
- auto process_name = process_prefix(process_no);
- for(auto i = 0; i < 5; ++i) {
- std::cout << process_name << " i - " << i << '\n';
- }
- }
- void child(std::vector<std::string> const& pipe_names, int process_no, int count) {
- auto process_name = process_prefix(process_no);
- std::clog << process_name + "started\n";
- auto pipes = open_pipes(pipe_names, process_no, count);
- sleep(1);
- auto time = 0;
- std::set<Message> queue;
- for(auto i = 0; i < 2; ++i) {
- std::clog << process_name + " wants to enter critical section\n";
- //Pi requests to enter critical section
- auto timestamp = ++time;
- auto msg = Message(Message::Type::Request, process_no, timestamp);
- queue.insert(msg);
- for(auto j = 0; j < count; ++j) {
- if (process_no != j) {
- Message::write(pipes[j], msg);
- std::cout << process_name + "sends message [" + std::to_string(msg) + "] to " + std::to_string(j) + '\n';
- }
- }
- auto responses_count = 0;
- while((responses_count != count - 1) || *queue.begin() != msg) {
- std::clog << process_name + "reading from " + pipes[process_no].name + "\n";
- auto rec = Message::read(pipes[process_no]);
- std::cout << process_name + "received message [" + std::to_string(rec) + "]\n";
- switch(rec.type) {
- case Message::Type::Request:
- {
- time = std::max(time, rec.clock) + 1;
- queue.insert(rec);
- auto response = Message(Message::Type::Response, rec.process, time);
- Message::write(pipes[rec.process], response);
- std::cout << process_name + "sends message [" + std::to_string(msg) + "] to " + std::to_string(rec.process) + '\n';
- break;
- }
- case Message::Type::Response:
- ++responses_count;
- break;
- case Message::Type::Exit:
- {
- rec.type = Message::Type::Request;
- queue.erase(rec);
- break;
- }
- }
- }
- critical(process_no);
- queue.erase(msg);
- msg.type = Message::Type::Exit;
- for(auto j = 0; j < count; ++j) {
- if(process_no != j) {
- Message::write(pipes[j], msg);
- std::cout << process_name + "sends message [" + std::to_string(msg) + "] to " + std::to_string(j) + '\n';
- }
- }
- }
- sleep(1);
- std::clog << process_name + "ended\n";
- }
- int main(int argc, char** argv) {
- if(argc != 3) { std::cerr << "./executable pipe_name children_count"; return EXIT_FAILURE; }
- auto pipe_prefix = std::string(argv[1]);
- auto children_count = atoi(argv[2]);
- try {
- auto pipe_names = generate_pipes(pipe_prefix, children_count);
- auto parent = true;
- for(auto i = 0; i < children_count; ++i) {
- switch(fork()) {
- case -1:
- throw std::runtime_error("Unable to create child");
- case 0:
- parent = false;
- child(pipe_names, i, children_count);
- i = children_count;
- break;
- default:
- std::clog << "Created child " + std::to_string(i) + '\n';
- break;
- }
- }
- //wait for children to execute
- if(parent) {
- for(auto i = 0; i < children_count; ++i) {
- std::clog << "Wait for child i: " << i << '\n';
- wait(NULL);
- std::clog << "Child i: " << i << " ended\n";
- }
- }
- }
- catch(std::runtime_error& e) {
- std::cerr << e.what() << '\n';
- return EXIT_FAILURE;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement