Linux multiprocess Programming II -- process creation and death

1, Process creation and related functions

1. Process creation

The system allows a process to create a new process. The new process is a sub process of the original process. The sub process can also create a new sub process to form a process tree structure model, and its related function is pid_t fork(void); The specific usage is as follows:

/*
        #include <sys/types.h>
        #include <unistd.h>

        pid_t fork(void);
        Role: used to copy and create child processes
        Return value:
            fork()The return value is returned twice, once in the parent process and once in the child process
            In the parent process: returns the child process id
            In child process: return 0
            Distinguish between parent and child processes by return value
            Failure: Return - 1 (in the parent process) and set errno. The number of processes may be online or the system memory may be insufficient


        Relationship between parent and child processes:
        difference:
            1.fork()The return value of the function is different
                Parent process > 0, child process id
                Child process = = 0
            2.pcb Data in:
                Current id, pid
                The id and ppid of the parent process of the current process

        common ground:
            In some states, the child process has just been created and no data has been written. At this time, the parent and child processes share
                -User area data
                -File descriptor table
            At the beginning, variables are shared. If data is modified, variables are not shared
*/
#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(){
    int num =10;
    //Create child process
    pid_t pid = fork();
    //Determine whether the parent process or the child process
    if (pid>0)
    {
        printf("pid:%d\n",pid);
        //If>0,Returns the process number of the child process, which is currently the parent process
        printf("i am parent process, pid:%d, ppid:%d\n", getpid(), getppid());
        printf("parent_num:%d\n", num);
        num+=10;
        printf("parent_num+=10:%d\n", num);

    }
    else if (pid==0)
    {
        //Is currently a child process
        printf("i am child process, pid:%d, ppid:%d\n", getpid(), getppid());
        printf("child_num:%d\n", num);
        num+=100;//Subprocess num With parent process num irrelevant
        printf("child_num+=100:%d\n", num);
    }
    else{
        perror("fork\n");
        return -1;
    }
    //for loop
    for (int i = 0; i < 3; ++i)
    {
        printf("i: %d, pid: %d\n",i , getpid());
        sleep(1);
    }
    return 0;
}

The parent and child processes share the kernel area, but the pid in the kernel area is different. User areas are not related to each other.

 

 

  2.exec function family

The function of exec family is to find the executable file according to the specified file name and use it to replace the contents of the calling process. In other words, it is to execute an executable file inside the calling process. The functions of the exec function family will not return after successful execution, because the entities calling the process, including code segments, data segments and stacks, have been replaced by new contents, leaving only some superficial information such as process ID. It looks like an old body, but it has injected a new soul. Only if the call fails, they will return - 1 and execute down from the call point of the original program. Common functions include int execl(const char *pathname, const char *arg);   int execlp(const char *file, const char *arg);

/*

        #include <unistd.h>

        int execl(const char *pathname, const char *arg);
        Parameters:
            -pathname:You need to specify the name of the executable file path (absolute path is recommended)
            -arg: String, that is, the parameters required by the executable file are obtained by the arg [] array of main
                The first parameter usually writes the name of the executable program, which has no practical effect
                The second and subsequent parameters are the list of parameters required by the executable program
                The parameter needs to end with NULL (called sentinel)
        Return value:
            Only when there is an error can there be a return value of - 1 and set errno. There is no return value after success (the original file is no longer executed)
*/

/*

        #include <unistd.h>

        int execlp(const char *file, const char *arg);
        Function: it will look for the executable file in the environment variable. If it is found, it will execute
        Parameters:
            -file:The name of the file in the environment variable
            -arg: String, that is, the parameters required by the executable file are obtained by the arg [] array of main
                The first parameter usually writes the name of the executable program, which has no practical effect
                The second and subsequent parameters are the list of parameters required by the executable program
                The parameter needs to end with NULL (called sentinel)
        Return value:
            Only when there is an error can there be a return value of - 1 and set errno. There is no return value after success (the original file is no longer executed)
*/

#include<stdio.h>
#include<unistd.h>


int main(){
    //Create a child process and execute in the child process exec Medium function
    pid_t pid = fork();
    if(pid>0){
        printf("i am parent process, pid: %d\n", getpid());
        sleep(1);
    }else if(pid==0){
        //Child process replacement
        execl("/usr/bin/ps","ps","aux",NULL);
        printf("i am child process, pid: %d\n",getpid());
    }
    for (int i = 0; i < 3; i++)
    {
        printf("i :%d, pid = %d\n", i, getpid());
    }
    return 0;
}

2, The demise of the process

1. The process exits normally

  

 

/*

        #include <stdlib.h>

        void exit(int status);


        #include <unistd.h>

        void _exit(int status);


        status Parameter: it is a status information when the process exits. It can be obtained when the parent process reclaims the resources of the child process.

*/
#include <unistd.h>
#include <stdlib.h>
#include<stdio.h>
int main(){

    printf("hello\n");
    printf("world");

    //_exit(0); Linux System functions do not refresh io buffer
    exit(0);//standard c The library will refresh io Buffer, use more
    return 0;
}

2. Orphan process

The parent process died, but the child process has not finished running. At this time, the orphan process will be adopted by the system init process. There is no harm in the orphan process.

  3. Zombie process

After each process ends, the user area data in its address space will be released, but the kernel area PCB must be released by the parent process. When the process terminates, the parent process is not recycled, and the child process PCB remains in the kernel and becomes a zombie process. The following code will create a zombie process, that is, the parent process does not end and the information occupied by the child process is not recycled. Zombie processes, as their names are, cannot be killed by the kill -9 command, and can only be recycled by forcibly ending the parent process. If a large number of zombie processes are generated, a limited number of system process numbers will be occupied, resulting in the inability to generate new processes, resulting in incalculable losses, which should be avoided.

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(){
    int num =10;
    //Create child process
    pid_t pid = fork();
    //Determine whether the parent process or the child process
    if (pid>0)
    {
        //The parent process keeps looping
        while(1){
            printf("i am parent process, pid:%d, ppid:%d\n", getpid(), getppid());
            sleep(1);
        }
        
    }
    else if (pid==0)
    {
        //Currently, it is a child process. Print directly and end
        printf("i am child process, pid:%d, ppid:%d\n", getpid(), getppid());
    }
    else{
        perror("fork\n");
        return -1;
    }
    //for loop
    for (int i = 0; i < 3; ++i)
    {
        printf("i: %d, pid: %d\n",i , getpid());
        sleep(1);
    }
    return 0;
}

4. Method to avoid zombie process -- process recovery command

When each process exits, the kernel releases all the resources of the process, including open files, occupied memory, etc. However, certain information is still reserved for it, which mainly refers to the information of the process control block PCB (including process number, exit status, running time, etc.). The parent process can get its exit status by calling wait or waitpid, and completely clear the process. The functions of wait() and waitpid() functions are the same. The difference is that the wait() function blocks. Waitpid() can be set not to block. Waitpid() can also specify which child process to wait for to end. Note: a wait or waitpid call can only clean up one child process, and a loop should be used to clean up multiple child processes.

pid_t wait(int *wstatus);
/*
        #include <sys/types.h>
        #include <sys/wait.h>
        pid_t wait(int *wstatus);
        -Function: wait for any sub process to end, recover status change information and release relevant resources
        -Parameters:
            int *wstatus: The status information when the process exits. The incoming address is an Int type address and the outgoing parameters.
        -Return value:
            -Successfully returned the recycled child process id
            -Failure returns - 1 (all child processes end)
        ----When the wait function is called, the process will be suspended until the child process exits or is awakened by a signal that cannot be ignored
        If there are no child processes or all the child processes have ended, return - 1
*/
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include<stdio.h>
int main(){
    //There is a parent process and five child processes need to be created
    pid_t pid;
    for (int i = 0; i < 5; i++){
        pid = fork();
        if(pid==0)break;//Avoid child process nesting
    }
    if(pid>0){
        //Parent process
        while(1){
            printf("parent , pid = %d\n", getpid());

            int st;
            int ret = wait(&st);
            if(ret == -1){
                break;
            }
            if(WIFEXITED(st)){
                //Is it normal to quit
                printf("Exit status code:%d\n",WEXITSTATUS(st));

            }
            if(WIFSIGNALED(st)){
                //Is it abnormal termination
                printf("Terminated by what signal:%d\n",WTERMSIG(st));
            }
            printf("child die, pid = %d\n", ret);
            sleep(1);
        }
    
    }else if (pid==0)
    {
        /* Subprocess */
        //while(1){
            printf("child, pid = %d, ppid = %d\n", getpid(), getppid());
            sleep(1);
        //}
        exit(1);
        
    }
    
    

    return 0;
}
pid_t waitpid(pid_t pid, int *wstatus, int options);
/*
        #include <sys/types.h>
        #include <sys/wait.h>
        pid_t waitpid(pid_t pid, int *wstatus, int options);
        Function: reclaim the child process of the specified process number, but you can set non blocking, that is, do not wait for the child process to terminate
        Parameters:
            -pid_t pid:
                pid>0:pid of a child process
                pid==0: Reclaim all child processes of the current process group
                pid==-1:Indicates that all child processes are recycled, which is equivalent to calling wait
                pid<-1: Reclaim a process group subprocess (the group number is the absolute value of this parameter)
            -int *wstatus:Recycling information
            -int options:Set blocking or non blocking
                0: block
                WNOHANG: Non blocking
        Return value:
            >0:Returns the id of the child process
            ==0: options=WNOHANG,Indicates that there are child processes alive
            ==-1: Error, or there are no child processes
*/


#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include<stdio.h>
int main(){
    //There is a parent process and five child processes need to be created
    pid_t pid;
    for (int i = 0; i < 5; i++){
        pid = fork();
        if(pid==0)break;//Avoid child process nesting
    }
    if(pid>0){
        //Parent process
        while(1){
            sleep(1);
            printf("parent , pid = %d\n", getpid());
            int st;
            int ret = waitpid(-1, &st, WNOHANG);
            if(ret == -1){
                break;
            }
            if(ret==0){
                continue;
            } else if (ret > 0){
                if(WIFEXITED(st)){
                //Is it normal to quit
                printf("Exit status code:%d\n",WEXITSTATUS(st));

            }
                if(WIFSIGNALED(st)){
                //Is it abnormal termination
                    printf("Terminated by what signal:%d\n",WTERMSIG(st));
            }
                printf("child die, pid = %d\n", ret);
            }
        }
    }else if (pid==0)
    {
        /* Subprocess */
        while(1){
            printf("child, pid = %d\n", getpid());
            sleep(1);
        }
        exit(0);
    }
    return 0;
}

The exit information macro is as follows (in the code st):

  

 

 

Tags: Linux

Posted on Sat, 04 Dec 2021 16:47:53 -0500 by MiniMonty