skip to Main Content

I need to fork many short life processes. (But I don’t want to wait until it is finished. Just let it run.). After some time, I receive error when executing fork (errno == 11). It looks like the forked processes still exists (at least they are visible in htop).

For instance, please consider the following example. I want to fork a process and then exit it shortly after.

#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <errno.h>
#include <signal.h>

void RunProc(){   
    pid_t pid = fork();
    if(pid == 0)
    {
        puts("fork with success");
        //no needed to reproduce issue. Used in my code to run some commands.
        //execvp()             
        exit(0);
    }
    else if (pid == -1) {
        printf("Could not start processn");
        printf("Errno: %dn", errno);
    }
    else {
    }
}
 
int main()
{
    while(true){
        RunProc();
    }

    int res = 0;
    int i = 5;
    res = scanf("%d", &i);
    res = printf("End of program %dn", i);
    return res;
}

At the beginning it runs correctly. After several minutes I receive only errors:

Could not start process
Errno: 11

And I’m not able to start new fork anymore.
I’m running it on Ubuntu 22.04

2

Answers


  1. You need to call one of the wait functions in the parent process, to reap the child-process when it exits.

    You could use e.g. waitpid with the WNOHANG flag to poll for child-process exit. Or use the SIGCHLD signal to learn when a child process have exited.

    There’s only a limited number of process-slots available in your system, if you don’t reap the child processes, they will fill up all the slots and lead to the error you get.

    As the fork manual page say about the EAGAIN error:

    A system-imposed limit on the number of threads was encountered.

    Login or Signup to reply.
  2. When process terminates, its PID and exit status still remains as a record in process table. This is so called zombie process. You can remove it by reading its status with one of wait() functions family, as described in sibling answer.

    If you don’t need to care about status of child processes, you can allow init to read their status and cleanup the table. When parent process terminates, init (process with PID 1) becomes parent of all its children processes by default. Thus you can use double fork to make init to be a parent of your processes:

    void RunProc(void)
    {
        pid_t pid = fork();
    
        if (pid == -1) {
            perror("fork()");
            return;
        }
    
        if (pid == 0)
        {
            // first level child
            pid_t pid = fork();
    
            if (pid == -1) {
                perror("fork()");
                _exit(1);
            }
            if (pid != 0) {
                // first level child just terminates
                _exit(0);
            }
    
            // second level child
            puts("fork with success");
    
            _exit(0);
        }
    
        // wait for first level child
        if (waitpid(pid, NULL, 0) == -1) {
            perror("wait()");
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search