16

I have a program that uses fork() to create a child process. I have seen various examples that use wait() to wait for the child process to end before closing, but I am wondering what I can do to simply check if the file process is still running.

I basically have an infinite loop and I want to do something like:

if(child process has ended) break;

How could I go about doing this?

Alex
  • 671
  • 3
  • 11
  • 25

4 Answers4

39

Use waitpid() with the WNOHANG option.

int status;
pid_t result = waitpid(ChildPID, &status, WNOHANG);
if (result == 0) {
  // Child still alive
} else if (result == -1) {
  // Error 
} else {
  // Child exited
}
Erik
  • 88,732
  • 13
  • 198
  • 189
  • So the ChildPID is the one I am using to differentiate between parent and child and result is a new pid_t that makes a new sub-process that watches for the child to exit? – Alex Mar 11 '11 at 21:46
  • No, ChildPID is the process ID of the child that `fork()` returned. `waitpid()` is just a function which returns a value: `0`, `ChildPid` or `-1` – Erik Mar 11 '11 at 21:49
  • Well, what I mean is I made a `pid_t` to say `pid=fork()`. Now to write code for my parent and child I have an if-else that checks `if(pid)` to identify the parent process, because in the parent process `pid` contains the child's pid number, and in the child `pid` contains `0`. So if I am understanding this correctly I believe that I should use `pid` where you have said to use `ChildPID`. – Alex Mar 11 '11 at 21:56
  • @Alex: Yes, your `pid` is the process ID of the child. – Erik Mar 11 '11 at 21:58
  • U need to use getpid() to get the process id of the child. using a -1 in place of childpid would work – Access Denied Oct 11 '12 at 08:44
  • What if `WIFSTOPPED` returns `true` in the `else` clause? Semantically, this does not mean that the child process has exited, and is rather suspended. So I'd say for completeness, one should add the corresponding check into the `else` clause. Same goes for `WIFCONTINUED`. – Alexander Shukaev May 11 '16 at 18:51
2

You don't need to wait for a child until you get the SIGCHLD signal. If you've gotten that signal, you can call wait and see if it's the child process you're looking for. If you haven't gotten the signal, the child is still running.

Obviously, if you need to do nothing unitl the child finishes, just call wait.

Gabe
  • 84,912
  • 12
  • 139
  • 238
2

EDIT: If you just want to know if the child process stopped running, then the other answers are probably better. Mine is more to do with synchronizing when a process could do several computations, without necessarily terminating.

If you have some object representing the child computation, add a method such as bool isFinished() which would return true if the child has finished. Have a private bool member in the object that represents whether the operation has finished. Finally, have another method private setFinished(bool) on the same object that your child process calls when it finishes its computation.

Now the most important thing is mutex locks. Make sure you have a per-object mutex that you lock every time you try to access any members, including inside the bool isFinished() and setFinished(bool) methods.

EDIT2: (some OO clarifications)

Since I was asked to explain how this could be done with OO, I'll give a few suggestions, although it heavily depends on the overall problem, so take this with a mound of salt. Having most of the program written in C style, with one object floating around is inconsistent.

As a simple example you could have a class called ChildComputation

class ChildComputation {

    public:
    //constructor
    ChildComputation(/*some params to differentiate each child's computation*/) : 
        // populate internal members here {
    }
    ~ChildComputation();

    public:
    bool isFinished() {
        m_isFinished; // no need to lock mutex here, since we are not modifying data
    }

    void doComputation() {
        // put code here for your child to execute
        this->setFinished(true);
    }

    private:
    void setFinished(bool finished) {
        m_mutex.lock();
        m_isFinished = finished;
        m_mutex.unlock();
    }

    private:
    // class members
    mutex m_mutexLock; // replace mutex with whatever mutex you are working with
    bool m_isFinished;
    // other stuff needed for computation
}

Now in your main program, where you fork:

ChildComputation* myChild = new ChildComputation(/*params*/);
ChildPID= fork();
if (ChildPID == 0) {
   // will do the computation and automatically set its finish flag.
   myChild->doComputation();
}
else {
   while (1) { // your infinite loop in the parent
       // ...

       // check if child completed its computation
       if (myChild->isFinished()) {
           break;
       }
   }

   // at the end, make sure the child is no runnning, and dispose of the object
   // when you don't need it.
   wait(ChildPID);
   delete myChild;
}

Hope that makes sense.

To reiterate, what I have written above is an ugly amalgamation of C and C++ (not in terms of syntax, but style/design), and is just there to give you a glimpse of synchronization with OO, in your context.

Alexander Kondratskiy
  • 4,156
  • 2
  • 30
  • 51
  • I'm not sure exactly how to make my child process into an object. This is the first time I have ever done this type of programming, so my understanding is still fairly basic. Right now I just have a main function that creates two pipes then forks and has an if-else statement using pid to separate the code for the parent and child processes. How could I go about making this object oriented? – Alex Mar 11 '11 at 21:41
  • If your problem is simple, maybe you don't even need to make it OO, I just assumed it since you put c++ as a tag. It really depends on the overall problem you are trying to solve. Erik's answer is the most appropriate for your current code. I'll add some stuff to my answer to clarify though. – Alexander Kondratskiy Mar 11 '11 at 21:49
  • That makes sense. I suppose it really is more of a C issue than a C++ issue. I'm just used to using C++ and am including some C++ functions in my program, but this part of the program really is more C-like. I suppose in the future I will label it C/C++. – Alex Mar 11 '11 at 22:21
0

I'm posting the same answer here i posted at as this question How to check if a process is running in C++? as this is basically a duplicate. Only difference is the use case of the function.

Use kill(pid, sig) but check for the errno status. If you're running as a different user and you have no access to the process it will fail with EPERM but the process is still alive. You should be checking for ESRCH which means No such process.

If you're running a child process kill will succeed until waitpid is called that forces the clean up of any defunct processes as well.

Here's a function that returns true whether the process is still running and handles cleans up defunct processes as well.

bool IsProcessAlive(int ProcessId)
{
    // Wait for child process, this should clean up defunct processes
    waitpid(ProcessId, nullptr, WNOHANG);
    // kill failed let's see why..
    if (kill(ProcessId, 0) == -1)
    {
        // First of all kill may fail with EPERM if we run as a different user and we have no access, so let's make sure the errno is ESRCH (Process not found!)
        if (errno != ESRCH)
        {
            return true;
        }
        return false;
    }
    // If kill didn't fail the process is still running
    return true;
}
Playdome.io
  • 3,137
  • 2
  • 17
  • 34