Linux: process exit and process wait wait, waitpid

1. Process exit

1.1 Introduction to process exit

Process exit scenario

  • The code is run and the result is correct
  • The code runs and the result is incorrect
  • Code terminates abnormally

Common exit methods for processes:

1. Normal termination (you can check the process exit code through echo $?):

  1. return from main
  2. call exit
  3. _exit

?: Saves the exit code when the latest child process completes execution.

2. Abnormal exit:

  • ctrl + c
  • Signal termination (explained later)

Why do we need an exit code?

In a multi-process environment, what is the purpose of a parent process creating a child process? It helps the parent process to do things. How does the child process do things? The parent process needs to know.

The return code of the main function can be obtained by the parent process and is used to determine the running result of the child process main. The main function returns 0, which means success, and non-0, which means failure. For what reason this process failed, we can return different numbers and use different numbers to represent different reasons.

1.2 _exit,exit 与 return

1. The _exit function is a system call: terminates the calling process

Note: Although status is int, only the lower 8 bits can be used by the parent process. So when _exit(-1) is executed on the terminal, $? is found and the return value is 255.

exit is a system call. When the process is terminated, the buffer will not be refreshed and the contents of the buffer will be discarded.

2. The exit function is a library function: allowing a normal program to terminate

_exit will also be called eventually inside exit , but before calling _exit, other work is also done: 

  1. All open streams are closed and all cached data is written. That is, the buffer is flushed and printf prints immediately.
  2. call_exit

3. return exit: it is a library function

  1. return is a more common way to exit a process. The main function's execution of return n is equivalent to the execution of exit(n), and the return value of main will be used as the parameter of exit.
  2. Return in the main function indicates the process exit, and return in other functions indicates the end of the function call.
  3. Return and exit are both library functions and will refresh the buffer.

1.3 C language error code: errno

According to different result phenomena, different exit codes are returned.

Error code vs exit code

  • Error codes usually measure the invocation of a library function or a system call.
  • The exit code is usually the exit result of a process when it exits.

When it fails, it is used to measure the detailed cause of the error in the function or process.

1.4 Abnormal issues

The code terminated abnormally, why did it terminate? When an exception occurs in a process, the essence is that the process received the corresponding signal and terminated itself.

We can manually use the kill command to send signal No. 11: segmentation fault to this process, causing the process to terminate abnormally.

Therefore, whether a process has an exception, we only need to see if a signal is received.

2. Process waiting

2.1 What is process waiting?

Through the wait/waitpid system call, the parent process waits for resource recycling of the child process.

2.2 Why wait?

  • As mentioned in the previous article, if the child process exits and the parent process is ignored, it may cause a "zombie process" problem, thereby causing a memory leak.
  • In addition, once the process becomes a zombie, it will be invulnerable, and the "kill without blinking" kill -9 will be useless, because no one can kill a dead process.
  • Finally, we need to know how well the tasks assigned by the parent process to the child process are completed. It is necessary to obtain the exit information of the child process by waiting for the process , two numbers, the exit code and the termination signal to determine whether the result is correct or incorrect, or whether it exited normally. But it is not necessary, and the system needs to provide such basic functions!
  • The parent process recycles the resources of the child process and obtains the exit information of the child process through process waiting.

2.3 How to wait

2.3.1 wait() method

#include<sys/types.h>
#include<sys/wait.h>


pid_t wait(int*status);


Return value:
Success: Returns the pid of the process being waited for. Failure (no child process): Returns -1.
Parameter:
Output parameter, obtains the exit status of the child process. If you don't care, you can set it to NULL.

About the parameter status  

  • Both wait and waitpid have a status parameter, which is an output parameter.
  • If NULL is passed, it means that the exit status information of the child process is not concerned. Otherwise, the operating system will feedback the exit information of the child process to the parent process based on this parameter.
  • Status cannot simply be treated as an integer, but can be treated as a bitmap. The specific details are as follows (only the lower 16 bits of status are studied)

The core dump flag is not something we care about here. 

Status of the three exit methods:

  • The code runs and the results are correct. The exit status is 0 and the termination signal is 0.
  • The code runs to completion and the results are incorrect. The exit status is not 0 and the termination signal is 0.
  • The code terminated abnormally. The exit status is 0, and the exit status here is meaningless. The termination signal is not 0.

Here the exit status and termination signal can be obtained using bit operations , and the exit code can also be obtained through system-defined macros:

  • WIFEXITED(status): If it is non-zero (true), it means that the process ended normally. (Check whether the process exited normally)
  • WEXITSTATUS(status): If WIFEXITED is non-zero (true), extract the child process exit code. (View the exit code of the process)

Code example:

 Results of the:

The function of the wait() function is to wait for any child process to end . The parent process uses blocking wait , which will wait for the child process to complete execution and become a zombie state. After wait() is recycled, the parent process will continue to execute.

2.3.2 waitpid() method

pid_ t waitpid(pid_t pid, int *status, int options);

return value:

  • >0: When returning normally, waitpid returns the collected process ID of the child process;
  • ==0: If the parameter options is set to WNOHANG, and waitpid finds that there are no exited child processes to collect during the call, 0 will be returned;
  • <0: If there is an error in the call, there is no child process, or the pid is entered incorrectly, then -1 is returned.

parameter:

  • pid: Pid = -1, wait for any child process, equivalent to wait . Pid > 0, wait for the child process whose process ID is equal to pid ( that is, specify the child process to be recycled ).
  • status: Already mentioned above.
  • options: 0: Indicates that the parent process uses blocking waiting and waits for the child process to finish executing the parent process before executing it . WNOHANG: If the child process specified by pid has not ended, the waitpid() function returns 0 and does not wait. The recycling adopts non-blocking polling mode. The purpose of using this option is that if the child process has not finished executing, the parent process does not need to be kept in the state. In the blocking wait state, the parent process can do its own thing.

Code example:

void Worker(int cnt)    
{
    printf("I am a child ,pid:%d , cnt :%d\n",getpid(),cnt);
}

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        //child;
        int cnt = 5;
        while(cnt)
        {
            Worker(cnt);    
            cnt--;    
            sleep(2);    
        }                                                                                                  
        exit(0);       
    }    
             
    //father        
    while(1)//非阻塞轮询                                                                                               
    {            
        int status = 0;    
        pid_t rid = waitpid(id, &status,WNOHANG);     
        if(rid>0)    
        {    
            //wait success,child quit now;    
            printf("child quit success,exit code:%d,exit signal:%d\n",(status>>8)&0xff,status&0x7f);    
            break;    
        }    
        else if(rid == 0) 
        {
            //wait success,but child not quit.
            printf("child is alive,wait agin,father do other thing....\n");
        }
        else
        {
            //wait failed,child unknow
            printf("wait failed\n");
            break;
        }
        sleep(1);                                                                                                       

    }
    return 0;
}

operation result:

Related questions:

How does the parent process know the exit information of the child process?

There are exit_code and exit_signal fields in the PCB. When the child process exits, the status Z needs to be modified, and the exit signal and exit code of the child process are written into the PCB, allowing the parent process to recycle and read.

This article is over! 

Guess you like

Origin blog.csdn.net/qq_72916130/article/details/135316873