Search code examples
c++classfork

Why does the child of this class does not print?


I have made a class that is supposed to handle a subprocess but when I put a test print inside nothing happens, can someone tell me why ?

I have tried different types of print and combinations of fflush but it didn't solve the problem.

Here are my files:

Kitchen.cpp

Kitchen::Kitchen()
{
    int wstatus;

    this->_pid = fork();
    if (this->_pid == 0) {
        std::cout << "child: " << this->_pid << std::endl;
    } else if (this->_pid == -1) {
        throw("No child");
    } else {
        std::cout << "parent: " << this->_pid << std::endl;
        waitpid(this->_pid, &wstatus, 1);
    }
}

Kitchen::~Kitchen()
{
    if (this->_pid > 0)
        kill(this->_pid, SIGKILL);
}

Kitchen.hpp

#pragma once

#include <signal.h>
#include <unistd.h>

class Kitchen {
    public:
        Kitchen();
        ~Kitchen();
    private:
        pid_t _pid;
};

Reception.cpp

int Reception::run_shell(void)
{
    this->_kitchens.push_back(Kitchen());
    return (0);
}

Reception.hpp

#pragma once

#include <iostream>
#include <sstream>
#include "Kitchen.hpp"

class Reception
{
    public:
        Reception();
        ~Reception();
        void repart(std::vector<Package> packed_order);
        bool is_order(std::string input);
        std::vector<Package> pack(std::string input);
        int run_shell(void);
    private:
        std::vector<Kitchen> _kitchens;
};

main.cpp

int main(void)
{
    Reception reception;
    return (reception.run_shell());
}

Right now only the parent prints where as I would like both process to print.

Note that this code works outside of the class.


Solution

  • is it better now ?

    Yes, better.


    I copied your code to my Lubuntu 18.04, and using g++ 7.3.0-27, got the thing to compile.

    The copied code on my system reproduced your error.

    Hmmm.

    So, I went looking for, and quickly found, my most recent experiment with fork. I do not understand why it works, and yours does not, they look similar enough to me.

    I use a switch instead of your nested if-then-else's ... perhaps there exists a glitch in the nested if-then-else's? a faulty char transfer? But I doubt it.


    So ... for pragmatic reasons, I (minimally?) changed your code to match my example.

    Perhaps you can ask a better question as to why this seems to work, and in your version does not.

    Hope this helps:

    #include "../../bag/src/dtb_chrono.hh"
    using  namespace std::chrono_literals;      // support suffixes like 100ms, 2s, 30us
    
    #include <iostream>
    using std::cout, std::cerr, std::flush, std::endl;
    
    #include <string>
    using std::string;
    
    #include <thread>
    using std::this_thread::sleep_for;
    
    #include <vector>
    using std::vector;
    
    #include <cstring>
    using std::strerror;
    
    #include <unistd.h>   // fork
    #include <sys/wait.h> // waitpid
    
    #include <cassert>
    
    
    class Kitchen
    {
       pid_t child_pid;
       time_t pt0; // child  start time 0
       time_t ct0; // parent start time 0
    
    public:
       Kitchen()
          {
             pt0 = time(0) + 2;
             ct0 = time(0) + 1;
    
             // On success, the PID of the child process is returned in the
             // parent, and 0 is returned in the child.
             //
             // On failure, -1 is returned in the parent, no child process is
             // created, and errno is set appropriately.
    
             child_pid = fork();
    
             switch (child_pid)
             {
    
             case -1: { errnoExit (errno, "\n  fork fail: ", -12); } break;
    
             case 0: // child
             {
                std::cout << "\n  i am child: " << child_pid << endl;
                ChildProcess();
             }
             break;
    
             default: // parent
             {
                std::cout << "\n  i am parent, child_pid: " << child_pid << flush;
                ParentProcess();
             }
    
             } // switch(child_pid)
    
          } // Kitchen
    
       ~Kitchen()
          {
             if (child_pid > 0)
             {   }; //  {  kill(child_pid, SIGKILL)};
          }
    
       void  ChildProcess(void)
          {
             int   i = 0;
             do {
                i += 1;
                cout  << "\n  child  " << i;
                std::this_thread::sleep_for(100ms);
                if (time(0) > ct0) break;
             }while (true);
             cout << "\n*** Child  complete ***" << '\n';
          }
    
       void  ParentProcess(void)
          {
             int   i = 0;
             do {
                i += 1;
                cout  << "\n  parent " << i ;
                std::this_thread::sleep_for(100ms);
                if (time(0) > pt0) break;
             }while (true);
             int wstatus;
             waitpid(child_pid, &wstatus, 1); // see output -
             // waitpid not effective because parent runs longer than child
             // but causes no harm ...
             //
             // TBD - when parent run is shorter than child?
             //       appears that parent end halts child?
             cout << "\n*** Parent complete ***" << '\n';
          }
    
    
    private:
    
       void errnoExit(int err_no, const string message, int id) {
          assert(0 != err_no);  cerr << message << strerror(err_no);
          assert(id < 0);       exit(id); }
    
    }; // class Kitchen
    
    
    class Reception
    {
    public:
       Reception() = default;
       ~Reception() = default;
    
       int operator()(int argc, char* argv[]) { return run_shell(argc, argv); }
    
       //void repart(std::vector<Package> packed_order);
       //bool is_order(std::string input);
       //std::vector<Package> pack(std::string input);
       int run_shell(int /*argc*/, char** /*argv[]*/)
          {
             _kitchens.push_back(Kitchen());
             return (0);
          }
    private:
       vector<Kitchen> _kitchens;
    }; // class Reception
    
    
    int main(int argc, char* argv[]) { return Reception()(argc, argv); }
    

    Typical Output:

      i am parent, child_pid: 6727
    
      i am child: 0
    
      parent 1
      child  1
      parent 2
      child  2
      parent 3
      child  3
      parent 4
      child  4
      parent 5
      child  5
      parent 6
      child  6
      parent 7
      child  7
      parent 8
      child  8
      parent 9
      child  9
      parent 10
      child  10
      parent 11
      child  11
      parent 12
      child  12
      parent 13
      child  13
      parent 14
      child  14
      parent 15
      child  15
      parent 16
      child  16
      parent 17
      child  17
      parent 18
      child  18
    *** Child  complete ***
      parent 19
      parent 20
      parent 21
      parent 22
      parent 23
      parent 24
      parent 25
      parent 26
      parent 27
      parent 28
    *** Parent complete ***