This chapter needs to master the following several functions Fork,exec family, _exit,wait,waitpid
1 Process Identifiers
#include <unistd.h>pid_t getpid (void); Returns:ProcessId ofCallingProcesspid_t getppid (void); Returns:parentProcessId ofCallingProcessuid_t getuid (void); Returns:real User ID ofCallingProcessuid_t geteuid (void); Returns:effective User ID ofCallingProcessgid_t getgid (void); Returns:realGroupId ofCallingProcessgid_t getegid (void); Returns:effectiveGroupId ofCallingProcess
2 Fork function
#include <unistd.h>pid_t fork(void); 0inofin1onerror
The fork function executes once but returns two times. The return value of the parent process is the process ID of the child process, and the return value of the child process is 0 (does not represent the process ID of the child process is 0)
The child process and the parent process do not share storage space, only a copy of the parent process.
Parent-Child process call order is indeterminate
#include "apue.h"intGlob =6;/ * External variable in initialized data * /CharBuf[] ="A write to stdout\n"; Int Main (void){int var;/ * Automatic variable on the stack * /pid_t pid;var= the;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 * /glob++;/ * Modify variables * / var++; }Else{Sleep (2);/ * Parent * /} printf ("pid =%d, Glob =%d, var =%d\n", Getpid (), Glob,var); Exit0);}
3 Vfork function
#include "apue.h"intGlob =6;/ * External variable in initialized data * /Int Main (void){int var;/ * Automatic variable on the stack * /pid_t pid;var= the; printf"Before vfork\n");/ * We don ' t flush stdio * / if(PID = vfork ()) <0) {Err_sys ("Vfork Error"); }Else if(PID = =0) {/ * Child * /glob++;/ * Modify Parent ' s variables * / var++; _exit (0);/ * Child terminates * /}/ * * Parent continues here. */printf"pid =%d, Glob =%d, var =%d\n", Getpid (), Glob,var); Exit0);}
and fork Two differences:
1. The child process runs in the parent process space before calling exec, sharing memory
2. Ensure that the child process runs first, the kernel causes the parent process to hibernate, so no sleep function
Exit and _exit are used to terminate a process normally, the main difference is that _exit will immediately enter the kernel, while exit performs some cleanup work (including executing various termination handlers, shutting down all standard I/O, etc., once the IO is closed, For example, printf and other functions will not output anything) before entering the kernel. These two functions have a certain effect on the parent-child process, and when a child process is created with vfork, the child process runs first in the address space of the parent process (which is not the same as fork), and if the child process calls exit, the parent process's IO is turned off.
Next we can make a small test, change vfork to fork, estimate glob=6,var=88. Because a child process modifies a replica
4 Wait and Waitpid functions
#include <sys/wait.h> wait(int*statlocwaitpidint*statlocint options);成功返回进程ID,出错返回-1
When a process terminates normally, the kernel sends a SIGCHLD signal to the parent process. Because the child process termination is an asynchronous event, the asynchronous signal is sent as well.
For processes that call wait and waitpid, the following happens:
(1) The child process is still running, blocking
(2) If the child process is terminated and is waiting for the parent process to get its terminating state, it gets the terminating state of the process and returns immediately
(3) If there are no child processes, an immediate error is returned
The difference between the two:
1. Wait causes its callers to block before the child process terminates, while Waitpid has an option that allows the caller to not block
2.Waitpid has several options to control the process it waits for
#include "apue.h"#include <sys/wait.h>Int Main (void) {pid_t pid;intStatusif(PID =Fork()) <0) Err_sys ("Fork Error");Else if(PID = =0)/* Child*/ Exit(7);if(wait(&status)! = PID)/*wait forChild*/Child process Termination Err_sys ("Wait Error"); Pr_exit (status);/ * and print its status * / if(PID =Fork()) <0) Err_sys ("Fork Error");Else if(PID = =0)/* Child*/Abort ();/ * Generates SIGABRT * / if(wait(&status)! = PID)/*wait forChild*/Err_sys ("Wait Error"); Pr_exit (status);/ * and print its status * / if(PID =Fork()) <0) Err_sys ("Fork Error");Else if(PID = =0)/* Child*/Status/=0;/ * Divide by 0 generates SIGFPE * / if(wait(&status)! = PID)/*wait forChild*/Err_sys ("Wait Error"); Pr_exit (status);/ * and print its status * / Exit(0);} Modify the code. The output status also allows it to output PID. Pr_exit (status) changed toprintf(“%d %d\ n ", status, PID);
Call Fork two times to avoid zombie processes
#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 the second child, our parent becomes init as soon * as we real parent calls exit () in the statement above . * here 'swhere we' d continue executing, knowing that when * we 'Re done, Init would reap OurStatus.*/ Sleep(2);//Ensure that the parent process executes firstprintf("second child, parent PID = %d\ n", Getppid ());Exit(0); }if(Waitpid(PID, NULL,0)! = PID)/*wait forFirst child*/Err_sys ("Waitpid Error");/* * we ' re the parent (the original process), we continue executing, * knowing that we are not the parent of th e second child. */ Exit(0);}
The second child process calls sleep to ensure that the first child process is terminated when the parent process ID is printed. If there is no sleep, it may execute first than the parent process, then the returned ID will be the parent process ID. Instead of the init process (a value of 1).
Run the program to get
$ ./a.out$ 1
5 exec function
When the process calls the EXEC function, the process's program is completely replaced with the new program, and the new program starts with the main function. Calling exec does not create a new process, so the process ID before and after does not change.
Fork creates a new process, exec executes a new program, exit and two wait functions handle termination and wait termination
#include <unistd.h>intEXECL (Const Char*pathname,Const Char*arg0, .../* (char *) 0 */);intExecvConst Char*pathname,Char*Constargv []);intExecle (Const Char*pathname,Const Char*arg0, .../* (char *) 0, char *const envp[] */);intExecve (Const Char*pathname,Char*ConstArgv[],Char*ConstENVP []);intEXECLP (Const Char*filename,Const Char*arg0, .../* (char *) 0 */);intEXECVP (Const Char*filename,Char*Constargv []);
#include "apue.h"#include <sys/wait.h>Char*env_init[] = {"User=unknown","Path=/tmp",NULL};intMainvoid) {pid_t pid;if(PID = fork ()) <0) {Err_sys ("Fork Error"); }Else if(PID = =0) {/ * Specify pathname, specify environment * / if(Execle ("/home/sar/bin/echoall","Echoall","Myarg1","MY ARG2", (Char*)0, Env_init) <0) Err_sys ("Execle Error"); }if(Waitpid (PID,NULL,0) <0) Err_sys ("Wait Error");if(PID = fork ()) <0) {Err_sys ("Fork Error"); }Else if(PID = =0) {/ * Specify filename, inherit environment * / if(EXECLP ("Echoall","Echoall","only 1 arg", (Char*)0) <0) Err_sys ("EXECLP Error"); } exit (0);}
Call Execle first in the program, which requires a pathname and a specific environment. The next call is EXECLP, which is passed to the new program with a file name.
8 (Process Control)