0

I've never worked with file descriptors and I'm a bit confused about some of this behavior. I'm also fairly new to concurrency and the documentation for these functions is fairly lacking.

My MessageReciever constructor opens a pty. Upon calling the Receive message, as I understand it, the code forks. The master should hit the next conditional and return from the function. I know this is happening because the code in main doesn't block. The child reads in the file descriptor, converts it to a string and saves it in a vector. Currently I'm printing the buffer directly but I also can print the last element in the vector and it acts basically the same. However, when I attempt to access this outside the class, in main, I get nothing. I thought this might be some type of concurrency problem, but I'm not really sure how to address.

CODE

#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <stdio.h>
#include <util.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string>
#include <vector>

class MessageReceiver
{
  public:
  MessageReceiver()
  {
    openpty(&master, &slave, NULL, NULL, NULL);
  }

  ~MessageReceiver()
  {
    close(master);
    close(slave);
  }

  void receiveMessage()
  {
    pid_t pid = fork();
    printf("PID = %d\n",pid);
    if(pid > 0)
    {
      fd_set rfds;
      struct timeval tv;
      tv.tv_sec = 0;
      tv.tv_usec = 0;
      char buf[4097];
      ssize_t size;
      size_t count = 0;

      while (1)
      {
        if (waitpid(pid, NULL, WNOHANG) == pid) 
        {
          break;
        }
        FD_ZERO(&rfds);
        FD_SET(master, &rfds);
        if (select(master + 1, &rfds, NULL, NULL, &tv)) 
        {
          size = read(master, buf, 4096);
          printf("Buffer = %s", buf);
          messageBuffer.push_back(std::string(buf));
          buf[size] = '\0';
          count += size;
        }
      }

    }

  }

  std::string getLastMessage()
  {
    std::string s;
    if(messageBuffer.size() > 0)
    {
      s = messageBuffer.back();
    }
    else
    {
      s = "NULL";
    }
    return s;
  }

  private:
  int master, slave;
  std::vector<std::string> messageBuffer;
};

int main()
{
  MessageReceiver m;
  m.receiveMessage();
  std::string lastMessage = m.getLastMessage();
  printf("Printing message buffer:\n");
  for(;;)
  {
    if(m.getLastMessage() != lastMessage)
    {
      printf("Message: %s\n", m.getLastMessage().c_str());
    }
  }
  return 0;
}

Initial output

PID = 8170
PID = 0
Printing message buffer:

Additional output when hello is echoed to the pty

Buffer = hello
mreff555
  • 1,049
  • 1
  • 11
  • 21
  • When you call `fork` the two new processes don't share memory between each other (usually). So even if the parent adds some messages to the buffer, the child won't see them because it has its own message buffer which is still empty. – user253751 Jun 19 '19 at 23:51
  • And even if the processes did share memory, or if this was a proper multi-threaded program, this is guaranteed to result in a crash, because there is absolutely no mutex protection whatsoever, and none of the C++ library classes are thread-safe. – Sam Varshavchik Jun 19 '19 at 23:54
  • Thats what I figured. Is there a way to join the threads. As for Mutex locks, I'm in the proof of concept phase. Be patient. – mreff555 Jun 20 '19 at 00:05
  • I think I found an answer to my question here: https://stackoverflow.com/questions/5656530/how-to-use-shared-memory-with-linux-in-c – mreff555 Jun 20 '19 at 00:10
  • Before messing with shared memory I'd make certain that fork is the right solution for the message-handling problem. You're already using `select`, can you not expand that to running a `select`-based server and keep all of the communications in one process or thread? – user4581301 Jun 20 '19 at 00:13
  • I tried messing with select, given the documentation is fairly limited. can you recommend a path forward? – mreff555 Jun 20 '19 at 00:21

0 Answers0