Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the ways to avoid zombie processes in Linux background development

2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces "what is the way to avoid zombie process in Linux background development". In daily operation, I believe that many people have doubts about the method of avoiding zombie process in Linux background development. I have consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer your doubts about "what is the way to avoid zombie process in Linux background development"! Next, please follow the editor to study!

First, what is the deadlock process?

In general, the program calls exit (including _ exit and _ Exit, the difference between them is not explained here), most of its memory and related resources have been released by the kernel, but this process item (entry) is still retained in the process table (process ID, exit status, occupied resources, etc.), you may ask, why bother to just release the resources? This is because sometimes its parent process wants to know its exit status. A child process is a zombie process, or a zombie process, before it exits but has not been "zombie" by its parent. If the parent process dies before the child process, then the child process will be adopted by the init process, in which case init is the parent process of the child process.

So once the parent process runs for a long time, but there is no call to wait or waitpid, and the SIGCHLD signal is not processed, there is no way for the init process to collect the corpse for the child process. At this time, the child process really becomes a "zombie".

Second, what is the difference between the zombie process and the orphan process?

The answer to this question is very simple, that is, the question of who dies first between father (father process) and son (child process)!

If the father dies while the son is alive, then the son becomes an orphan and the son will be adopted by init. In other words, the init process acts as the father of the son, so when the son dies, the init process will collect the body for him.

If the son dies while the father is still alive, if the father does not collect the body of the son, then the son will become a zombie process.

Third, the harm of the process of death?

The PID of the dead process is still occupied, which means that a large number of child processes will occupy the full process table items, making it impossible for later processes to fork.

The kernel stack of a dead process cannot be released (1K or 2K size), so why keep its kernel stack? because at the bottom of the stack, there is a thread_info structure, which contains the struct_task structure, which contains some exit information.

IV. Ways to avoid the process of deadlock

After searching the Internet, it is concluded that there are three ways:

The signal (SIGCHLD, SIG_IGN) shown in the ① program is called to ignore the SIGCHLD signal, so that after the process ends, the kernel will wai and release resources.

② fork twice, the child process of the first fork exits directly after the completion of the fork, so the child process obtained by the second fork has no father, it will be automatically adopted by the ancestor init, and init will be responsible for releasing its resources, so that there will be no "zombies".

③ wait the child process and release their resources, but the parent process generally has no time to watch and wait for the child process to exit, so it is generally handled by the way of signal. When the SIGCHLD signal is received, the wait operation is called in the signal processing function to release their resources.

Fifth, the analysis and summary of each method to avoid deadlock.

First of all, let's take a look at a program that generates a zombie process, zombie.c:

# include # include # include int main (int argc, const char * argv []) {int I; pid_t pid; for (I = 0; I

< 10; i++) { if ((pid = fork()) == 0) /* child */ _exit(0); } sleep(10); exit(EXIT_SUCCESS); } 运行程序,在10s睡眠期间使用ps查看进程,你会发现有10个标记为"defunct"的僵尸进程: 接下来看第一种方法,程序avoid_zombie1.c如下: #include #include #include #include #include int main(int argc, const char *argv[]) { pid_t pid; if (SIG_ERR == signal(SIGCHLD, SIG_IGN)) { perror("signal error"); _exit(EXIT_FAILURE); } while (1) { if ((pid = fork()) == 0) /* child */ _exit(0); } exit(EXIT_SUCCESS); } 程序运行期间通过ps命令的确没有发现僵尸进程的存在。 在man文档中有这段话: Note that even though the default disposition of SIGCHLD is "ignore", explicitly setting the disposition to SIG_IGN results in different treatment of zombie process children. 意思是说尽管系统对信号SIGCHLD的默认处理就是"ignore",但是显示的设置成SIG_IGN的处理方式在在这里会表现不同的处理方式(即子进程结束后,资源由系统自动收回,所以不会产生僵尸进程),这是信号SIGCHLD与其他信号的不同之处。 在man文档中同样有这样一段话: The original POSIX standard left the behavior of setting SIGCHLD to SIG_IGN unspecified. 看来这个方法不是每个平台都使用,尤其在一些老的系统中,兼容性不是很好,所以如果你在写一个可移植的程序的话,不推荐使用这个方法。 第二种方法,即通过两次fork来避免僵尸进程,我们来看一个例子avoid_zombie2.c: #include #include #include #include #include int main(int argc, const char *argv[]) { pid_t pid; while (1) { if ((pid = fork()) == 0) { /* child */ if ((pid = fork()) >

0) _ exit (0); sleep (1); printf ("grandchild, parent id =% ld\ n", (long) getppid ()); _ exit (0) } if (waitpid (- 1, NULL, 0)! = pid) {perror ("waitpid error"); _ exit (EXIT_FAILURE);}} exit (EXIT_SUCCESS);}

This is indeed an effective method, but I think this method is not suitable for network concurrent servers, because the efficiency of fork is not high.

Finally, let's take a look at the third and most general method.

Let's take a look at our test program avoid_zombie3.c first.

# include # include void avoid_zombies_handler (int signo) {pid_t pid; int exit_status; int saved_errno = errno; while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0) {/ * do nothing * /} errno = saved_errno } int main (int argc, char * argv []) {pid_t pid; int status; struct sigaction child_act; memset (& child_act, 0, sizeof (struct sigaction)); child_act.sa_handler = avoid_zombies_handler; child_act.sa_flags = SA_RESTART | SA_NOCLDSTOP; sigemptyset (& child_act.sa_mask) If (sigaction (SIGCHLD, & child_act, NULL) =-1) {perror ("sigaction error"); _ exit (EXIT_FAILURE);} while (1) {if ((pid = fork ()) = 0) {/ * child process * / _ exit (0) } else if (pid > 0) {/ * parent process * /}} _ exit (EXIT_SUCCESS);}

First of all, you need to know three things:

1. When the signal processing function of a signal is called, the signal is blocked by the operating system (the default sa_flags does not set the SA_NODEFER flag).

two。 When the signal processing function of a signal is called, when the signal is blocked, the signal occurs again and again, then the operating system does not queue them, but only keeps the first and subsequent discarded.

There's one more thing we need to know.

3. Wait series functions have nothing to do with signal SIGCHLD, that is, wait series functions are not driven by signal SIGCHLD.

At this time, someone must be in doubt, since the signal will be discarded, how can we ensure that all zombie processes can be recovered?

With regard to this problem, we can understand it this way, when the child process ends, no matter whether the child process generates the SIGCHLD signal or the child process generates the SIGCHLD signal, and whether the parent process receives the SIGCHLD signal or not, it has nothing to do with the fact that the child process has terminated, that is, the child process termination has nothing to do with the signal, but the operating system will send the signal SIGCHLD to the parent process when the child process terminates. Inform its child process of the termination message, so that the parent process can do the corresponding operation. The purpose of the wait series of functions is to retrieve the information left in the process list when the child process terminates, so any time you call while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0), you can retrieve all the zombie process information (see the following program). But the reason why it is dealt with here in the signal processing function is that when the child process ends is an asynchronous event, and the signal mechanism is used to deal with the asynchronous event, so when the child process ends, its residual information can be quickly recovered, so that a large number of zombie processes will not be accumulated in the system.

It can also be understood this way: the system strings all zombie processes together to form a zombie process linked list, and while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0) is used to empty the linked list until waitpid () returns 0, indicating that there are no zombie processes, or-1, indicating an error (when the error code errno is ECHILD, it also indicates that there are no zombie processes).

Knowing the above knowledge points, you can understand why while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0) can recycle all zombie processes.

We can add the corresponding print information to the above signal processing function:

Static int num1 = 0 static int num2 = 0; void avoid_zombies_handler (int signo) {pid_t pid; int exit_status; int saved_errno = errno; printf ("num1 =% d\ n", + + num1); while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0) {printf ("num2 =% d\ n", + + num2);} errno = saved_errno }

Print the results you will find that when num1 increments by 1, that is, each call to the signal processing function, num2 will generally increase a lot, that is, while loops many times, so although some SIGCHLD signals are discarded, we do not have to worry about the residual information of the child process will not be recovered. When you exit the while loop, it is proved that there are no zombie processes in the system at this time, so after exiting the signal handler, the only blocked SIGCHLD signal will trigger the signal handler again, so we don't have to worry. We do not guard against the worst-case scenario, that is, all the previous signals are discarded, and only the last SIGCHLD signal is captured, thus triggering the signal processing function, so we do not have to worry, because the while loop will retrieve all the zombie process information at once, but this time there are much more times, of course, this is only hypothetical. This is not the case in a general system (you can refer to the last program example in this article).

To prove that the wait system function has nothing to do with the signal SIGCHLD, we can do a simple experiment with the following code:

# include # include int main (int argc, char * argv []) {int I; pid_t pid; for (I = 0; I

< 5; i++) { if ((pid = fork()) == 0) /* child */ _exit(0); } sleep(10); while (waitpid(-1, NULL, WNOHANG) >

0) {/ * do nothing * /} sleep (10); _ exit (EXIT_SUCCESS);}

The following is the print result:

You can see that five zombie processes were accumulated in the system at the first sleep, and all five zombie processes were withdrawn at the second sleep. This also clearly shows the advantage of using signal processing function, that is, it can ensure that the system will not accumulate a large number of zombie processes, and it can quickly clean up the zombie processes in the system.

At this point, the study on "what is the way to avoid zombie processes in Linux background development" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report