linux下我們可以調用fork函數創建子進程,創建的子進程將會得到父進程的數據空間、堆、棧......副本(採用寫時複製機制),子進程將會繼承父進程的信號掩碼、信號處理方式、當前工作目錄、會話id、組id......。當子進程退出時父進程應當及時獲取子進程退出狀態,否則,如果父進程是一直在運行,那麼子進程的退出狀態將一直保存在內存中,直到父進程退出才釋放。
我們可以使用如下幾種方法避免殭屍進程的產生:
1.在fork後調用wait/waitpid函數取得子進程退出狀態。
2.調用fork兩次(第一次調用產生一個子進程,第二次調用fork是在第一個子進
程中調用,同時將父進程退出(第一個子進程退出),此時的第二個子進程的父
進程id爲init進程id(注意:新版本Ubuntu並不是init的進程id))。
3.在程序中顯示忽略SIGCHLD信號(子進程退出時會產生一個SIGCHLD信號,我
們顯示忽略此信號即可)。
4.捕獲SIGCHLD信號並在捕獲程序中調用wait/waitpid函數。
方法一:
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0) {
perror("fork error");
return EXIT_FAILURE;
} else if (0 == pid) {
printf("[%ld] child process is running...\n", (long)getpid());
_exit(0);
}
//sleep(15);
if (waitpid(pid, NULL, 0) < 0) {
perror("waitpid error");
return EXIT_FAILURE;
}
for (; ;) {
pause();
}
return EXIT_SUCCESS;
}
方法二:
#include <sys/wait.h>
#include "../common/common.h"
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0) {
perror("fork error");
return EXIT_FAILURE;
} else if (0 == pid) {
printf("first child is running..\n");
/**在第一個子進程中再次fork***/
if ((pid = fork()) < 0) {
perror("fork error");
return EXIT_FAILURE;
} else if (pid > 0) {/**父進程退出**/
printf("[%ld] first child is exit...\n", (long)getpid());
_exit(0);
}
sleep(2);/**確保父進程先運行**/
printf("second process pid: %ld, second process's parent pid: %ld\n", (long)getpid(), (long)getppid());
printf("[%ld] is exit..\n", (long)getpid());
_exit(0);
}
/***獲得第一個子進程的退出狀態***/
if (waitpid(pid, NULL, 0) < 0) {
perror("waitpid error");
return EXIT_FAILURE;
}
for(;;)
pause();
return EXIT_SUCCESS;
}
方法三:
#include <signal.h>
#include "../common/common.h"
int main(void)
{
/***顯示忽略SIGCHLD信號****/
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
perror("signal error");
return EXIT_SUCCESS;
}
pid_t pid;
int i;
/**產生10個子進程***/
for (i=0; i<10; ++i) {
if ((pid = fork()) < 0) {
perror("fork error");
return EXIT_FAILURE;
} else if (0 == pid) {
_exit(0);
}
sleep(2);
continue;
}
for (; ;)
pause();
return EXIT_SUCCESS;
}
方法四:
#include <signal.h>
#include <sys/wait.h>
#include "../common/common.h"
void sig_chld(int signo);
int main(void)
{
/**捕獲此信號, 此刻系統會立刻檢測是否有次信號產生**/
if (signal(SIGCHLD, sig_chld) == SIG_ERR) {
handler_err("signal error to SIGCHLD");
}
pid_t pid;
int i;
for (i=0; i<10; i++) {
if ((pid = fork()) < 0) {
handler_err("fork error");
} else if (0 == pid) {
printf("child pid: %d\n", getpid());
_exit(0);
}
sleep(1);
continue;
}
for (; ;) {
pause();
}
return EXIT_SUCCESS;
}
/**捕獲到信號後會立刻執行此段代碼***/
void sig_chld(int signo)
{
printf("receive child signal\n");
if (waitpid(-1, NULL, 0) < 0) {
perror("waitpid error");
}
if (signal(SIGCHLD, sig_chld) == SIG_ERR) {
perror("signal error to SIGCHLD");
}
}