UNIX advanced environment programming (9) Process Control-fork, vfork, zombie Process, wait and waitpid, vforkwaitpid
This chapter includes the following content:
- Create a new process
- Program execution)
- Process termination)
- Various process IDS
1. Process Identifiers)
Each process has a unique identifier (process ID ).
The process ID can be reused. If a process is terminated, its process ID will be recycled by the system, but it will be delayed, prevent the new process identified by the process ID from being mistaken as a previous process.
Three processes with special IDs:
- Process ID 0: scheduler Process, kernel Process.
- Process ID 1: init Process, which is the final startup of the kernel boot program and is responsible for starting the Unix system. Corresponding System File/sbin/init.
- Process ID 2: pagedaemon, responsible for Page Management of virtual memory.
Functions related to various process IDs:
Function declaration:
#include <unistd.h>
pid_t getpid(void); // Returns: process ID of calling process
pid_t getppid(void); // Returns: parent process ID of calling process
uid_t getuid(void); // Returns: real user ID of calling process
uid_t geteuid(void); // Returns: effective user ID of calling process
gid_t getgid(void); // Returns: real group ID of calling process
gid_t getegid(void); // Returns: effective group ID of calling process
The various IDs here are described in the third article, http://www.cnblogs.com/suzhou/p/4295535.html
2 fork Function
The fork function is used to create a new process for an existing process.
Function declaration:
#include <unistd.h>
pid_t fork(void);
Function details:
Example:
# Include "apue. h"
Int globvar = 6;/* external variable in initialized data */
Char buf [] = "a write to stdout \ n ";
Int
Main (void)
{
Int var;/* automatic variable on the stack */
Pid_t pid;
Var = 88;
If (write (STDOUT_FILENO, buf, sizeof (buf)-1 )! = Sizeof (buf)-1)
Err_sys ("write error ");
Printf ("before fork \ n");/* we don't flush stdout */
If (pid = fork () <0 ){
Err_sys ("fork error ");
} Else if (pid = 0) {/* child */
Globvar ++;/* modify variables */
Var ++;
} Else {
Sleep (2);/* parent */
}
Printf ("pid = % ld, glob = % d, var = % d \ n", (long) getpid (), globvar,
Var );
Exit (0 );
}
Execution result:
A process with a pid of 12291 is a sub-process, and 1 is added to the variables glob and var.
When the output is redirected to a file, we find that the results are not the same as those directly output to the terminal:
Cause:
- Function write does not use caching. Therefore, write is called before fork is called, and the result is directly output to the standard output;
- If the standard output is connected to the terminal, it is line buffered; otherwise, it is full buffered );
- In the first example, the line feed causes printf to flush the data written to the standard output to the terminal (line buffering, new lines, leading to the previous line being printed );
- In the second example, if we redirect the standard output to a file, the full buffer is used. The printf data is cached in the buffer and is not printed. In fork, buffer is also copied, so that both parent and child processes have a standard IO buffer );
- The second printf in the program prints the new data from append to the end of the existing data in the buffer, and then displays the printed results in the second example.
File Sharing)
When the fork function is called, all opened file descriptors of the parent process are copied to the child process, including file offset ).
When the Parent and Child processes write files at the same time, their operations will update the same file offset, add the child process to write part of the data to the file, and update the file offset, when the parent process writes data, it uses a new offset to avoid overwriting the data written by the child process.
Shows the file shared by the parent and child processes:
We can find that the parent and child processes have the same file descriptor and there is no other synchronization method, so their output may be mixed up (intermixed ).
After fork, there are two common methods to process file descriptors owned by Parent and Child processes:
- The parent process waits for the child process to complete.
- The Parent and Child processes work independently to disable unwanted file descriptors.
In addition to the description of the opened file, other child processes that inherit from the parent process include:
Different Parent and Child processes include:
- The return value of fork is different.
- Different Process IDS
- The parent process ID of a process is different.
- The values of tms_utime, tms_stime, itms_cutime, and itms_cstime of sub-processes are set to 0.
- The filelock of the parent process is not inherited by the quilt process.
- Sub-process pending signals is set to null
3 vfork
Vfork and fork have the same return values.
Differences between vfork and fork:
- Function purpose: the subprocess created by vfork is used to allow the subprocess to execute a new program.
- Copy operation: instead of copying the address space of the parent process, it runs directly in the address space of the parent process until the child process calls exec or exit.
- Efficiency: Therefore, the execution efficiency of vfork is higher than that of fork because it does not have the copy operation.
- Uncertain results: if the child process modifies data, calls a function, or does not call the exec or exit methods, uncertain results will occur.
- Run the sub-process first: vfork ensures that the sub-process runs first
Example:
# Include "apue. h"
Int globvar = 6;/* external variable in initialized data */
Int
Main (void)
{
Int var;/* automatic variable on the stack */
Pid_t pid;
Var = 88;
Printf ("before vfork \ n");/* we don't flush stdio */
If (pid = vfork () <0 ){
Err_sys ("vfork error ");
} Else if (pid = 0) {/* child */
Globvar ++;/* modify parent's variables */
Var ++;
_ Exit (0);/* child terminates */
}
/* Parent continues here */
Printf ("pid = % ld, glob = % d, var = % d \ n", (long) getpid (), globvar,
Var );
Exit (0 );
}
Running result:
4. process exit and zombie Process
Normal exit: three functions exit,
If the child process does not exit normally, the kernel ensures that the abnormal exit status of the process is recorded. The parent process of the child process can obtain the abnormal exit status by calling the wait or waitpid function.
If the parent process is terminated before the child process, the init process becomes the parent process of the child process. To ensure that each process has a parent process.
If a sub-process is terminated first (abnormal termination or normal exit), the kernel will save some information about the sub-process, including the process pid, the status at the Process Termination, And the CPU time occupied by the process, at the same time, the kernel clears the memory occupied by the process and closes all opened file descriptors. The parent process can check this information to obtain the termination status of the child process.
If a child process is terminated first, and no parent process calls waitpid to obtain information about the child process, the child process becomes a zombie process. Run the ps command to view information about the zombie process.
If the parent process is the init process, the abnormal termination of the child process will not become a zombie process, because the init process will call the wait function for all its child processes to obtain the termination status of the child process.
5 wait and waitpid Functions
When the child process is terminated, the kernel sends a SIGCHLD signal to the parent process. The default behavior of the parent process is to ignore this signal. The parent process can also set a signal processing function. When this signal is captured, this processing function is called, the following sections describe signal-related concepts.
The functions of wait and waitpid described in this section are as follows:
- If the sub-process is running, it is blocked;
- If the child process is terminated and the child process's termination status is obtained by the parent process, the function immediately returns the termination status;
- If the process does not have any child process, an error is returned.
Note that if we call the wait function after receiving the SIGCHLD signal, the function will return immediately. Otherwise, the wait function is blocked.
Function declaration:
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
// Both return: process ID if OK, 0,or -1 on error
Differences between two functions:
- The wait function will be blocked until a sub-process is terminated. The options parameter of the waitpid function can be specified not to be blocked;
- The waitpid function can choose not to block, and can specify to wait for a sub-process to terminate.
Function details:
- If a child process is terminated and becomes a zombie process, the wait function immediately returns the Status of the Child process;
- If a process calls the wait () function and blocks multiple sub-processes, the wait () function returns when one sub-process terminates;
- The statloc parameter is an integer pointer. If this parameter is not null, the termination status of the sub-process is saved in the integer to which this parameter points. If we do not care about the termination status of the process, pass in null in statloc;
Return Value check:
Use the four macros to check the wait and waitpid functions to obtain the terminated status of the sub-process, such as the exit status and signal value.
The following table describes the four macros:
The effect of pid value on waitpid function behavior:
- Pid =-1: The behavior is the same as that of wait. wait for any sub-process to terminate.
- Pid> 0: Wait for the process with the pid to terminate
- Pid = 0: Wait for any sub-process with the same process group number as the called process to terminate
- Pid <-1: Wait for any sub-process whose process group number is equal to pid to terminate
Value of option:
The waitpid function provides three features not available for wait:
- Waitpid allows us to wait for a specific process;
- Waitpid provides the wait function of the non-blocking version;
- The option parameters WCONTINUED and WUNTRACED provide support for the system's job control.
Example:
# Include "apue. h"
# Include <sys/wait. h>
Int
Main (void)
{
Pid_t pid;
If (pid = fork () <0 ){
Err_sys ("fork error ");
} Else if (pid = 0) {/* first child */
If (pid = fork () <0)
Err_sys ("fork error ");
Else if (pid> 0)
{
Exit (0);/* parent from second fork = first child */
}
/*
* We're re the second child; our parent becomes init as soon
* As our real parent callexit () in the statement above.
* Here's where we 'd continue executing, knowing that when
* We're done, init will reap our status.
*/
Sleep (2 );
Printf ("second child, parent pid = % ld \ n", (long) getppid ());
Exit (0 );
}
If (waitpid (pid, NULL, 0 )! = Pid)/* wait for first child */
Err_sys ("waitpid error ");
/*
* We're re the parent (the original process); we continue executing,
* Knowing that we're not the parent of the second child.
*/
Exit (0 );
}
Execution result:
Result Analysis:
Here we fork twice, because when we want to fork a sub-process, and we don't want the parent process to block in the wait function, if you do not want the child process to become a zombie process because the parent process does not call the wait function to exit first, fork will be two times and the first child process will be exited, so that the parent process can exit in time, the parent process of the second child process becomes the init process.
Summary
This article describes fork, vfork, botnets, wait, and waitpid functions, which are important concepts and functions in unix environments and are frequently asked during interviews.
The next article includes:
- Interpreter files)
- System function)
References:
Advanced Programming in the UNIX Envinronment 3rd