Necessity of process waiting
As mentioned before, if the child process exits, if the parent process is ignored, it may cause the problem of a “zombie process” and cause a memory leak.
In addition, once a process becomes a zombie, it is invulnerable, and the “kill without blinking” kill -9 can do nothing, because no one can kill a dead process. Finally, we need to know how the tasks assigned by the parent process to the child process are completed. For example, whether the child process finishes running, whether the result is correct or not, or whether it exits normally. The parent process reclaims the resources of the child process and obtains the exit information of the child process by means of process waiting
The method of process waiting
View through the man manual process
man 2 wait
wait() function
#include<sys/types.h> #include <sys/wait.h> pid_t wait(int*status); return value: Successfully returns the pid of the process being waited for, and returns -1 on failure. parameter: Output parameter, get the exit status of the child process, if you don't care, you can set it to NULL
Let’s test the wait() function
Next, observe the process status, first run
while :; do ps axj | head -1 & amp; & amp; ps ajx | grep mytest | grep -v grep; sleep 1; echo "--------------- -"; done
Next execute the program
View the process status while executing the program
In this way, the phenomenon cannot be observed, and the code should be improved.
waitpid() function
pid_t waitpid(pid_t pid, int *status, int options); return value: When returning normally, waitpid returns the process ID of the collected child process; If the option WNOHANG is set, and waitpid finds that there are no exited child processes to collect during the call, it returns 0; If there is an error in the call, -1 is returned, and errno will be set to the corresponding value to indicate the error; parameter: pid: Pid=-1, wait for any child process. Equivalent to wait. Pid > 0. Wait for a child process whose process ID is equal to pid. status: WIFEXITED(status): True if this is the status returned by a normally terminated child process. (Check to see if the process exited normally) WEXITSTATUS(status): If WIFEXITED is non-zero, extract the exit code of the child process. (Check the exit code of the process) options: WNOHANG: If the child process specified by pid has not ended, the waitpid() function returns 0 and does not wait. If it ends normally, the ID of the child process is returned.
1. If the child process has exited, when calling wait/waitpid, wait/waitpid will return immediately, release resources, and obtain the exit information of the child process.
2. If wait/waitpid is called at any time and the child process exists and is running normally, the process may be blocked.
3. If the child process does not exist, an error will be returned immediately.
Get subprocess status
Both wait and waitpid have a status parameter, which is an output parameter filled by the operating system.
If NULL is passed, it means that the exit status information of the child process is not concerned. Otherwise, the operating system will feed back the exit information of the child process to the parent process according to this parameter.
The status cannot be simply viewed as an integer, but can be viewed as a bitmap. The details are as follows (only the lower 16 bits of the status are studied):
The following is to get the exit code
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> int main() { pid_t id = fork(); if (id == 0) { int cnt = 5; while (cnt) { printf("I am a child process, I am still alive, I still have %dS, pid:%d, ppid:%d\ ", cnt--, getpid(), getppid()); sleep(1); } exit(107); } // parent process int status = 0; pid_t ret_id = waitpid(id, & status, 0); printf("I am the parent process, waiting for the success of the child process, pid:%d, ppid:%d, ret_id:%d, child exit code:%d\ ", getpid(), getppid(), ret_id, (status >> 8) & 0xFF); return 0; }
Where status>>8 & amp;0xff get the integer value
The following is to get the exception signal code
Get the abnormal signal status & amp; 0x7f to get the integer value
The exit code is 0, we create an exception, and check the exception signal
Let’s continue to change the program to make the program infinite loop
An infinite loop can also kill a process.
While the parent process is waiting for the child process, it can also do other things
If the child process does not exit, let the parent process do other things, write a program below to test it
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #define TASK_NUM 10 typedef void (*func_t)(); // function pointer func_t other_task[TASK_NUM] = {NULL}; // Preset a batch of tasks void sync_disk() { printf("This is a task to refresh data!\ "); } void sync_log() { printf("This is a synchronous log task!\ "); } void net_send() { printf("This is a network sending task!\ "); } // Load the task function pointer into the task list int LoadTask(func_t func) { int i = 0; for (; i < TASK_NUM; i ++ ) { if (other_task[i] == NULL) break; } if (i == TASK_NUM) return -1; else other_task[i] = func; return 0; } // Initialize task list void InitTask() { for (int i = 0; i < TASK_NUM; i ++ ) other_task[i] = NULL; LoadTask(sync_disk); LoadTask(sync_log); LoadTask(net_send); } // Execute all tasks in the task list void RunTask() { for (int i = 0; i < TASK_NUM; i ++ ) { if (other_task[i] == NULL) continue; other_task[i](); } } int main() { // create child process pid_t id = fork(); if (id == 0) // code executed by the child process { int cnt = 5; while (cnt) { printf("I am a child process, I am still alive, I still have %dS, pid:%d, ppid:%d\ ", cnt--, getpid(), getppid()); sleep(1); } exit(107); // The child process exits and returns 107 } // code executed by the parent process InitTask(); // Initialize task list while (1) { int status = 0; pid_t ret_id = waitpid(id, & amp;status, WNOHANG); // Check the status of the child process if (ret_id < 0) { printf("waitpid error!\ "); exit(1); } else if (ret_id == 0) // child process is still running { RunTask(); // Execute all tasks in the task list sleep(1); continue; } else // the child process has exited { printf("I am the parent process, waiting for the success of the child process, pid:%d, ppid:%d, ret_id:%d, child exit code:%d, child exit signal:%d\ ", getpid(), getppid (), ret_id, (status >> 8) & amp; 0xFF, status & amp; 0x7F); } } return 0; }
This program means that before the end of the child process, when the parent process is still idle, let the parent process do something else while waiting.
WIFEXITED get exit signal
WEXITSTATUS get exit code
Determine whether the child process exits normally, exit normally, and obtain the exit code through WEXITSTATUS(status)
Judging whether to exit normally, according to the signal, if the signal is received, it is an abnormal exit, judged by WIFEXITED(status)
Exit normally, the signal is 0, exit abnormally, we kill the process halfway to see the signal code
Specific code implementation
The blocking and waiting mode of the process
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> int main() { pid_t pid; pid = fork(); if (pid < 0) { printf("%s fork error\ ", __FUNCTION__); return 1; } else if (pid == 0) { // child printf("child is run, pid is : %d\ ", getpid()); sleep(5); exit(257); } else { int status = 0; pid_t ret = waitpid(-1, & amp;status, 0); // blocking wait, wait 5S printf("this is test for wait\ "); if (WIFEXITED(status) & amp; & amp; ret == pid) { printf("wait child 5s success, child return code is :%d.\ ", WEXITSTATUS(status)); } else { printf("wait child failed, return.\ "); return 1; } } return 0; }
The non-blocking waiting method of the process
WNOHANG is one of the options of the waitpid() function in Linux, which instructs the function not to block while waiting for a child process state change, i.e. return immediately instead of waiting if there is no child process state change available.
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> int main() { pid_t pid; pid = fork(); if (pid < 0) { printf("%s fork error\ ", __FUNCTION__); return 1; } else if (pid == 0) { // child printf("child is run, pid is : %d\ ", getpid()); sleep(5); exit(1); } else { int status = 0; pid_t ret = 0; do { ret = waitpid(-1, & amp;status, WNOHANG); // non-blocking wait if (ret == 0) { printf("child is running\ "); } sleep(1); } while (ret == 0); if (WIFEXITED(status) & amp; & amp; ret == pid) { printf("wait child 5s success, child return code is :%d.\ ", WEXITSTATUS(status)); } else { printf("wait child failed, return.\ "); return 1; } } return 0; }