在Ubuntu中,僵尸進程是由于子進程先于父進程結束,而父進程沒有正確地回收子進程的資源而產生的。為了避免僵尸進程的產生,可以采取以下措施:
wait()
或waitpid()
系統調用等待子進程結束。這樣可以確保父進程在子進程結束后正確地回收其資源。#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
// 子進程
// ... 執行任務 ...
exit(0);
} else if (pid > 0) {
// 父進程
int status;
waitpid(pid, &status, 0); // 等待子進程結束并回收資源
} else {
// fork失敗
perror("fork");
}
return 0;
}
SIGCHLD
信號。當子進程結束時,操作系統會發送SIGCHLD
信號給父進程。在信號處理器中調用waitpid()
或wait()
來回收子進程資源。#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void sigchld_handler(int signum) {
int status;
pid_t pid;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
printf("Child process %d exited with status %d\n", pid, WEXITSTATUS(status));
}
}
int main() {
struct sigaction sa;
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
pid_t pid = fork();
if (pid == 0) {
// 子進程
// ... 執行任務 ...
exit(0);
} else if (pid > 0) {
// 父進程
// ... 處理其他任務 ...
while (1) {
sleep(1);
}
} else {
// fork失敗
perror("fork");
exit(1);
}
return 0;
}
fork()
創建子進程時,可以考慮使用fork()
的擴展函數forkpty()
,它創建一個偽終端對,并返回子進程的文件描述符。這樣可以避免僵尸進程的產生,因為偽終端會自動回收子進程的資源。#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pty.h>
int main() {
int master_fd, slave_fd;
pid_t pid;
pid = forkpty(&master_fd, &slave_fd, NULL, NULL, NULL);
if (pid == 0) {
// 子進程
close(master_fd);
// ... 執行任務 ...
execl("/bin/sh", "sh", NULL);
perror("execl");
exit(1);
} else if (pid > 0) {
// 父進程
close(slave_fd);
// ... 處理其他任務 ...
} else {
// forkpty失敗
perror("forkpty");
exit(1);
}
return 0;
}
通過以上方法,可以有效地避免僵尸進程的產生。