C/C++ linux fork() and exec()

2020-04-16 04:55发布

问题:

I'm use fork() to create child process. From child process I am use exec() to launch new process. My code as below:

   ......
   pid = fork();
   if (pid > 0) {
       WriteLog("Parent Process");
       //Do something
   } else if (pid == 0) {
       WriteLog("Child process");
       int return = execl(ShellScript);
       if ( return == -1 ) 
          WriteLog("Launch process fail");
   } else {
       WriteLog("Can't create child process");
   }
   ......

Note: WriteLog function will be open file, write log, and close file. (It is flushed) ShellScript will launch new process c/c++.

I run my program for long run and the code above is called many times. And sometime (rarely) there are problem happen that the new process can't launch successful although the child process is created successfully (I have checked carefully). And one thing is extremely misunderstand when this problem happen that the "Child process" log can't printed although the child process is created successful.

In normal case (there are not error happen) the number of times print the "Child process" and "Parent process" log are the same.

In abnormal case, they are not the same although the child process always create successfully.The "Launch process fail" and "Can't create child process" log aren't printed in this case. Please help me for consult.

回答1:

Remember that stdio(3) is buffered. Always call fflush(NULL); (see fflush(3) for more) before fork. Add a \n (newline) at end of every printf(3) format string (or else, follow them by fflush(NULL); ...).

The function execl(3) (perhaps you want execlp?) can fail (so sets errno on failure).

} else if (pid == 0) {
   printf("Child process\n");
   fflush(NULL);
   execl("/bin/foo", "foo", "arg1", NULL);
   // if we are here execl has failed 
   perror("Launch process fail");
}

On error, fork(2) fails by returning -1 and sets errno(3) (see also perror(3) and strerror(3)). So your last else should be

} else {
    perror("Can't create child process");
    fflush(NULL);
}

You might want to use strace(1) (notably as strace -f yourprog ...) to understand the involved syscalls (see syscalls(2)...)

Your WriteLog should probably use strerror (on the errno value saved at beginning of WriteLog ....). I suggest something like

 void WriteLog(const char* msg) {
   int e = errno;
   if (e) 
     syslog (LOG_ERR, "%s [%s]", msg, strerrno(e));
   else
     syslog (LOG_ERR, "%s", msg);
 }

See syslog(3).

There are limits on the number of fork-ed processes, see setrlimit(2) with RLIMIT_NPROC and the bash ulimit builtin.

Read also Advanced Linux Programming.