The difference between fork+exec and System,popen

Source: Internet
Author: User
Tags exit in

1. Fork + exec

Fork is used to create a child process. When a program calls the fork function, the system prepares the previous three segments for a new process, first, the system allows the new process to use the same code snippet as the old process, because the program is still the same, and for the data segment and stack segment, the system copies a copy to the new process, so that All the data for the parent process can be left to the child process, but once the child process starts running, it inherits all the data from the parent process, but the data is actually separated and no longer affects each other, that is, no data is shared between them. If two processes want to share what data, it is necessary to use a different set of functions (SHMGET,SHMAT,SHMDT, etc.) to operate. Now, there are two processes, for the parent process, the fork function returns the subroutine's process number, and for the subroutine, the fork function returns zero, so that for the program, as long as the return value of the fork function is determined, you know whether you are in the parent or child process.

In fact, most UNIX systems currently do not have a real copy on the implementation. In general, the CPU is the "page" for the allocation of space, like Intel's CPU, the page is usually 4K byte size, regardless of whether the data segment or stack segment is composed of many "pages", the fork function to copy the two segments, but "logical", not "physical", that is, When the fork is actually executed, the data and stack segments of the two processes in the physical space are still shared, and when a process writes some data, the data between the two processes is different, and the system separates the "pages" from the physical. The overhead of the system can be minimized.

Vfork, like fork, also creates a child process, but it does not copy the address space of the parent process completely into the child process and does not replicate the page table. Because the child process calls exec immediately, the address space is not stored. However, before calling exec or exit in a child process, he runs in the space of the parent process.

Why there is vfork, because the previous fork when it creates a child process, will create a new address space, and copy the resources of the parent process, and often in the child process exec call, so that the previous copy work is a waste of effort, in this case, the smart man came up with vfork , it produces the child process has just begun to share the address space with the parent process (in fact, the concept of the thread), because this time the child process in the parent process of the address space run, so the child process can not write operations, and in the son "Occupy" the House of Lao Tzu, to wronged Lao Tzu, let him rest (blocking), Once the son executes exec or exit, the equivalent son buys his own house, this time is equivalent to the separation.

Another difference between vfork and fork is that vfork guarantees that the child process runs first, and the parent process may be scheduled to run after she calls exec or exit. If the child process relies on further actions of the parent process before invoking these two functions, it causes a deadlock.

Thus, this system call is used to launch a new application. Second, the child process runs directly in the stack space of the parent process after vfork () returns and uses the parent process's memory and data. This means that the child process may break the data structure or stack of the parent process, resulting in a failure.

To avoid these problems, you need to make sure that once you call Vfork (), the child process does not return from the current stack frame, and the Exit function cannot be called if the child process changes the data structure of the parent process. Child processes must also avoid altering any information in global data structures or global variables, because these changes can make it impossible for the parent process to continue.

In general, if an application does not call EXEC () immediately after fork (), it is necessary to do a careful check before fork () is replaced with vfork ().

After the child process is created with the fork function, the child process often calls an EXEC function to execute another program, and when the process calls an EXEC function, the process is completely substituted by the new program, and the new program starts from its main function, because calling exec does not create a new process, so the process ID Does not change, exec simply replaces the current process's body, data, heap, and stack with another new program.

Once a process calls the Exec class function, it is itself "dead", the system replaces the code snippet with the new program's code, discards the original data segment and stack segment, and assigns new data segment and stack segment to the new program, the only one left is the process number, that is, for the system, or the same process, But it's already another program. However, some of the Exec class functions also allow the inheritance of information such as environment variables, which can be obtained through the parameters of a subset of functions in the Exec series.

2. System

The system can be seen as fork + execl + waitpid. The system () function is powerful, and many people use it to understand the principle of the Linux version of the system function of the source code:


#include
#include
#include
#include

int system (const char * cmdstring)

{
pid_t pid;
int status;

if (cmdstring = = NULL) {

return (1);
}


if (PID = fork ()) <0) {

status =-1;
}


else if (PID = 0) {

Execl ("/bin/sh", "sh", "-C", Cmdstring, (char *) 0);

-exit (127); This statement is not executed if the child process is performing normally

}

else{

while (Waitpid (PID, &status, 0) < 0) {

if (errno! = einter) {

status =-1;

Break

}

}

}

return status;

}


First analysis of the principle, and then look at the code above you can see the understanding:
When the command accepted by system is NULL, it is returned directly, otherwise fork out a subprocess, because fork is returned in two processes: parent and child processes, here to check that the returned Pid,fork returns 0 in the child process, the PID of the child process is returned in the parent process, The parent process uses WAITPID to wait for the child process to end, the child process is called Execl to start a program instead of itself, execl ("/bin/sh", "sh", "-C", Cmdstring, (char*) 0) is the calling shell, the path of the shell is/ Bin/sh, the subsequent strings are arguments, and then the subprocess becomes a shell process, and the shell parameter is cmdstring, which is the parameter that the system accepts. The shell in Windows is the command, and presumably everyone is familiar with what the shell has done after accepting the command.

If you do not understand the above, then I explain the principle of fork: When a process a calls fork, the system kernel creates a new process B, and the memory image of a is copied to the process space of B, because A and B are the same, then how do they know that they are the parent or child process, The return value of the fork knows that it also says that fork returns 0 in the child process, and the PID of the child process is returned in the parent process.

The situation in Windows is similar, that is, EXECL changed a smelly and long name, the name of the parameter also changed to see the dizzy, I found the prototype in MSDN, to show you:

HInstance ShellExecute (
HWND hwnd,
LPCTSTR Lpverb,
LPCTSTR Lpfile,
LPCTSTR Lpparameters,
LPCTSTR Lpdirectory,
INT nShowCmd
);

usage See below:

ShellExecute (NULL, "open", "C://a.reg", NULL, NULL, SW_SHOWNORMAL);


You might wonder if there's a parameter in ShellExecute that passes the parent process environment variable Lpdirectory,linux EXECL is not, because EXECL is the compiler's function (to some extent, hides the specific system implementation), In Linux it will then generate a call to the Linux system Execve, the prototype is shown below:
int Execve (const char * file,const char **argv,const char **envp);

See here you will understand why system () accepts the environment variables of the parent process, but after changing the environment variable with system, system one returns the main function or not. The reason from the implementation of the system can be seen, it is achieved by generating a new process, from my analysis can see that there is no process communication between the parent process and the child process, the child process naturally cannot change the parent process environment variables.

With respect to the return value, if system () fails when calling/bin/sh, it returns 127, and the other reason for failure returns-1. If the return value is 0, the call succeeds but the child process does not appear. If the argument string is a null pointer (null), a value other than 0 is returned. If the system () call succeeds, the return value after executing the shell command is returned, but this return value may also be 127 of the return of the system () call to/bin/sh failure, so it is better to check the errno again to confirm that the execution was successful.

The return value of the shell command can be obtained by wexitstatus (STAT). The macro definition that processes the return value is in, including (stat is the return value of Waitpid ()):
wifexited (STAT) Non Zero if child exited normally.
Non 0 if subroutine exits normally
Wexitstatus (STAT) exit code returned by child
The subroutine returns the exit value
wifsignaled (STAT) Non-zero If child is terminated by a signal
Not 0 if a child process is ended by a signal
WTERMSIG (STAT) signal number, terminated child
Signal number of the end child process
wifstopped (STAT) Non-zero if child is stopped
Not 0 if the child process is stopped
Wstopsig (STAT) Number of signal that stopped child
Stops the signal number of the child process.
wifcontinued (STAT) Non-zero If status is for continued child
Non 0 if the status is a child process that continues to run
Wcoredump (STAT) if wifsignaled (stat) is Non-zero, which is non-zero if the process leftbehind a core dump.
If wifsignaled (stat) is nonzero and the process produces a core dump, this is also nonzero.

3, Popen

Popen () is also often used to execute a program.

FILE *popen (const char *command, const char *type);
int Pclose (FILE *stream);

The Popen () function starts a process by creating a pipeline and invokes the shell. Because pipelines are defined as unidirectional, the type parameter can only be defined as read-only or write-only, not both, and the resulting stream is read-only or write-only. The command parameter is a string pointer to a string that ends with a null terminator that contains a shell command. This command is sent to/bin/sh with the-c parameter, which is executed by the shell. The type parameter is also a pointer to a string ending with a null terminator, which must be ' r ' or ' W ' to indicate whether it is read or write.

The return value of the Popen () function is a normal standard I/O stream that can only be closed with the pclose () function instead of the fclose () function. Writes to this stream are converted to standard input for command commands; The standard output of command commands is the same as calling Popen (), which is the same as the process of the function, unless it is changed by command. Conversely, reading a "Popen" stream is equivalent to reading the standard output of the command, while the command's standard input is the same as calling Popen, which is the same process as the function.

Note that the output stream of the Popen function is fully buffered by default.

The Pclose function waits for the associated process to end and returns the exit state of a command command, just like the WAIT4 function

#include

int main (int argc, char *argv[])
{
Char buf[128];
FILE *pp;

if (pp = Popen ("Ls-l", "r") = = = NULL)
{
printf ("Popen () error!/n");
Exit (1);
}

while (Fgets (buf, sizeof buf, pp))
{
printf ("%s", buf);
}
Pclose (PP);
return 0;
}

The difference between fork+exec and System,popen

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.