https://blog.csdn.net/liuxingen/article/details/47057539
Linux System () and Popen () differences 1. System () and Popen () Introduction
In Linux we can execute a shell command through system (), and Popen () is also executing shell commands and communicating through pipes and shell commands.
System (), Popen () to us to deal with the fork, exec, waitpid and so on a series of processing process, let us only need to focus on the final return results (function return value). 2. System (), Popen () source code
First let's look at the differences between the two functions in the source code (pseudocode).
int system (const char *command) {struct sigaction sa_ignore, sa_intr, Sa_quit;
sigset_t Block_mask, Orig_mask;
pid_t pid;
Sigemptyset (&block_mask);
Sigaddset (&block_mask, SIGCHLD); Sigprocmask (Sig_block, &block_mask, &orig_mask); 1.
Block SIGCHLD Sa_ignore.sa_handler = sig_ign;
sa_ignore.sa_flags = 0;
Sigemptyset (&sa_ignore.sa_mask); Sigaction (SIGINT, &sa_ignore, &sa_intr); 2. Ignore SIGINT signal sigaction (Sigquit, &sa_ignore, &sa_quit); 3.
Ignore sigquit signal switch (PID = fork ()) {case-1: return-1;
Case 0:sigaction (SIGINT, &sa_intr, NULL);
Sigaction (Sigquit, &sa_quit, NULL);
Sigprocmask (Sig_setmask, &orig_mask, NULL);
Execl ("/bin/sh", "sh", "-C", command, (char *) 0);
Exit (127); Default:while (Waitpid (PID, NULL, 0) = = 1) 4.
Wait child process Exit {if (errno!= eintr) {break; return 0;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 The 23 24 25 26 27 28 29 30 31 32 33 34 35 36
Above is a not complete system function source code, the following needs our attention and the Popen difference part already uses the numeral to indicate.
static pid_t *childpid = NULL; /* ptr to array allocated at Run-time */static int maxfd; * FROM our Open_max (), {Prog OpenMAX} */#define SHELL "/bin/sh" FILE * popen (const char *cmdstring, const char
*type) {int i, pfd[2];
pid_t pid;
FILE *FP; /* Only allow "R" or "W" */if ((Type[0]!= ' R ' && type[0]!= ' W ') | | type[1]!= 0) {errno = Einv AL;
/* Required by POSIX.2 */return (NULL); } if (childpid = = NULL) {///////////////////Allocate zeroed out array for child
S */maxfd = Open_max ();
if (Childpid = calloc (maxfd, sizeof (pid_t)) = = null) return (NULL); } if (pipe (PFD) < 0) return (NULL); /* errno set by pipe ()/if (PID = fork ()) < 0) return (NULL); /* errno set by fork ()/else if (PID = 0) { /* Child */if (*type = = ' R ') {Close (pfd[0]);
if (pfd[1]!= Stdout_fileno) {dup2 (pfd[1], Stdout_fileno);
Close (pfd[1]);
} else {close (pfd[1]);
if (Pfd[0]!= Stdin_fileno) {dup2 (pfd[0], Stdin_fileno);
Close (pfd[0]);
}/* Close all descriptors in childpid[] */for (i = 0; i < maxfd; i++)
if (childpid[i] > 0) Close (i);
Execl (SHELL, "sh", "-C", Cmdstring, (char *) 0);
_exit (127);
}/* Parent */if (*type = = ' R ') {Close (pfd[1]);
if (fp = Fdopen (pfd[0], type) = = null) return (NULL);
else {close (pfd[0]);
if (fp = Fdopen (pfd[1], type) = = null) return (NULL); } Childpid[fileno (FP)] = pid;
/* Remember child pid for this FD */return (FP); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26-27--28 29---30 31--32 33 34 35 36 37 38-39 40 41 42 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65-66
Above is the Popen source code. 3. Implementation process
From the above source can see system and Popen are executed a similar operation flow, is roughly fork->execl->return. But we see the system calling the process while it is executing waits for the shell command to finish (Waitpid waits for the child to finish) before returning, but Popen does not have to wait for the shell command to complete. We can understand that system is executing serially, and that the calling process has abandoned "control" during execution, popen for parallel execution.
The subprocess in the Popen no one gave it a "corpse". Yes, if you don't call pclose after calling Popen then this subprocess could become "zombie".
Above we did not give Pclose source code, in fact, according to the system's source code can almost guess that Pclose's source is the system in part 4 of the content. 4. Signal Processing
We saw that the system was dealing with SIGCHLD, SIGINT, and Sigquit, but there was no signal processing in the popen.
SIGCHLD is a signal to the parent process when the subprocess exits, and why the system () is shielding the sigchld signal to refer to the summary of the system function, waitpid (or wait), and the sigchild relationship, summed up for system () The call is able to exit in a timely manner and to get the child process's exit status correctly (the child process is successfully reclaimed).
Popen no shielding sigchld, the main reason is that Popen is "parallel". If we mask sigchld when we call Popen, if we invoke the process between Popen and pclose, we create additional child processes and the calling process registers the SIGCHLD signal processing handle to handle the recycle of the child process (WAITPID) Then this recycle job will block until Pclose calls. This also means that if the calling process performs a wait () operation before Pclose, the state of the child process created by Popen can be acquired, so that the (waitpid) subprocess fails when the call to Pclose, returns 1, and sets errno to ECHLD. Mark Pclose cannot get child process status.
The reason for shielding SIGINT and Sigquit in System () can continue to refer to the summary of the system function mentioned above, and the reason for not masking SIGINT, sigquit in the Popen () function is also because Popen is "parallel" and cannot affect other "parallel" Process. 4. Function
From the above section we have basically analyzed the two functions, the difference between the two functions is also more obvious, system is the execution of the shell command to return the final success, Popen execute the command and through the pipeline and shell command to communicate. Note
In the privileged (setuid, setgid) process, be careful not to use system and popen.