Preface : When writing a multi-process program, we should understand how the operating system kernel does when creating a child process. When a new child process is created through the fork function, the kernel copies the contents of the user address space of the parent process to the child process, so that the parent process has its own separate user space and does not affect the corresponding variable in the child process when the value of the variable is repaired by the parents. However, to improve efficiency, Linux uses the cow (copy on write) algorithm, when the child process is created, the parent-child process has the same address space, only the cow identity is set in the page table, and only a physical page is requested for the child process when the parent process or child process performs a write operation. Copies the contents of the page that contains the corresponding data in the parent process space to the physical page, and then maps the page to the appropriate location in the child process's user address space. In addition, the child process inherits other resources from the parent process, such as the file descriptor and working directory that the parent process opens, because the child process can inherit the file descriptor of the parent process, so that the communication between the processes is implemented in a way that communicates with the pipeline. The code area of the child process and the parent process, as well as the initial data, are identical, except that the PID returned by the fork function has different values in the parent-child process, so the parent-child process will perform different results depending on the PID's branching statement. If we just want to use a sub-process to complete a certain part of the function, when the function is completed we should immediately use the exit or return function to end the child process, otherwise, if the child process is created in a loop, and does not use Exit or return to launch, then the child process, Executes the code in the loop just like the parent process, and then the child process creates the child process, infinite loop, with a detailed example of the server-side code behind it.
Process creation and exit
Related APIs
pid_t fork ()//#include <unistd.h> Create process
void exit (int status)//#include <stdlib.h> exit process, call atexit registered function on exit, register first call, Exit function also call fclose function on demand close open file stream
int atexit (void (*func) (void))//#include <stdlib.h> function called when the process registration is exited
void _exit (int status)//#include <unistd.h> Direct exit process
#include <sys/types.h>#include<stdio.h>#include<stdlib.h>intglob=Ten;Static voidMy_exit1 (void)//call function when process exits{printf ("pid=%d first Exit handler\n", Getpid ());}Static voidMy_exit2 (void) {printf ("pid=%d Second Exit handler\n", Getpid ());}intMain () {intLocal; pid_t pid; Local=8; if(Atexit (my_exit1)! =0)//The call function that is registered for the process at exit is also shared by the quilt process, which is first registered after the call{perror ("atexit"); } if(Atexit (my_exit2)! =0) {perror ("atexit"); } if((Pid=fork ()) = =0) {printf ("Child pid is%d\n", Getpid ()); When a child process executes a task, try to exit with exit, otherwise the child process created in the parent process may cause unknown behavior if it is in a loop.}Else if(pid>0) {Sleep (Ten); Glob++; Local--; printf ("Father PID is%d\n", Getpid ()); } Else{perror ("Fork"); } printf ("pid=%d,glob=%d,localar=%d\n", Getpid (), glob,local);//This piece of code is shared by the parent process return 0;//you can also use Exit (0)}
Loading an executable file image
#include <unistd.h>
int execl (const char *path,const char *arg,...); L means the command line argument is composed of multiple strings ending in 0, and V means that the command line argument is composed of a string array ending with 0
int execle (const char *path,const char *arg,..., char *const envp[]); e indicates the specified environment table amount, the original environment variable does not work
int EXECLP (const char *file,const char *arg,...); P indicates that the executable image file is found in the environment variable path path
int Execv (cosnt char *path,char *const argv[]);
int Execve (const char *path,char *const Argv[],char *const envp[]);
int EXECVP (const char *file,char *const argv[]);
Path represents the path to the executable file, and Arg represents the command-line arguments
TESTEXEC.C called program
#include <stdio.h>intglob= -;extern Char**environ;intMainintargcChar*argv[]) { intLocal= -; intK; Char**ptr=environ; Glob++; Local++; printf ("&glob=%x,&local=%x\n", &glob,&local);//Print the address of a variableprintf"argc=%d\n", ARGC); for(k=0; k<argc;++k) {printf ("argv[%d]\t%s\n", K,argv[k]);//Print command line arguments } for(ptr=environ;*ptr!=0;++ptr) {printf ("%s\n", *ptr);//Print Environment Variables } return 0;}
Useexec.c
#include <stdio.h>#include<unistd.h>intMain () {Char*nenv[]={"Name=value","Next=nextvale",(Char*)0}; Char*nargv[]={"testexec","param1","param2",(Char*)0}; Command line parameters are terminated with 0 pid_t pid; PID=Fork (); Switch(PID) { Case 0: Execve ("./testexec", nargv,nenv);//Specify environment variables, the original environment variables do not work//execl ("./testexec", "Testexec", 0); //do not specify the environment table amountPerror ("exec"); Exit (1); Case-1: Perror ("Fork"); Exit (1); default: Wait (NULL); printf ("exec is completed\n"); Exit (0); }}
Wait for the child process to end
#include <sys/types.h>
#include <sys/wait.h>
pid_t Wait (int * status)//pause execution until a child process completes, return to process PID successfully, otherwise return-1
pid_t waitpid (pid_t pid,int *status,int options)//wait for the specified sub-process to end, options specify the wait mode
return value: If Wnohang is set and No child process is found, 0 is returned, error 1
The meaning of PID
Pid<-1 wait for processes in the process group that the PID represents
Pid=-1 wait for any child process
Pid=0 waiting for the process to be in the same group as the process
Pid>0 Waiting for process identity
The meaning of options
Wnohang//indicates no blocking
wuntraced//Returns when there are child processes at the end
An echo Server service-side example TCPSERVER.C
#include <stdio.h>#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/inch.h>#include<unistd.h>#include<sys/wait.h>#definePORT 4008#defineBACKLOG 10#defineBUFSIZE 4096//voidProcessChar*cmd);intMainintargcChar*argv[]) { intLSOCKFD,RSOCKFD; structsockaddr_in Lsocket,rsocket; if(Lsockfd=socket (Af_inet,sock_stream,0)) <0) {perror ("Socket"); Exit (1); } lsocket.sin_family=af_inet; Lsocket.sin_port=htons (PORT); Lsocket.sin_addr.s_addr=Inaddr_any; Bzero (& (Lsocket.sin_zero),8); if(Bind (LSOCKFD, (structSOCKADDR *) &lsocket,sizeof(structSOCKADDR)) <0) {perror ("Bind"); Exit (1); } if(Listen (Lsockfd,backlog) <0) {perror ("Listen"); Exit (1); } intSin_size=sizeof(structsockaddr); intCount=0; while(1) {printf ("Wait for connecting!\n"); if(Rsockfd=accept (LSOCKFD, (structSOCKADDR *) &rsocket,&sin_size) <0) {perror ("Accept"); Continue; } Count++; printf ("someone connect!,current people%d\n", Count); if(!Fork ()) { CharStr[bufsize]; intnumbytes=0; while(1) { if((Numbytes=recv (rsockfd,str,bufsize-1,0)) <0) {perror ("recv"); Break; } Str[numbytes]=' /'; if(strcmp (str,"quit")==0) {printf ("Client quit!\n"); Break; } printf ("receive a message:%s\n", str); if(Send (Rsockfd,str,strlen (str),0) <0) {perror ("Send"); Break; }} close (RSOCKFD); Exit (0); } while(Waitpid (-1, Null,wnohang) >0)//This will not block if the third parameter is wuntraced, it will block{Count--; printf ("someone quit!,current people have%d\n", Count); } } return 0;}
Linux multi-Process programming example