반나절을 보냈는데 execl
통화로 시작한 대시가 왜 좀비로 변했는지 아직도 알 수 없었습니다.
다음은 최소한의 테스트 사례입니다. 저는 자식을 포크하고 std를 복사합니다.[입력, 출력, 오류]설명자 및 시작쉿.
#include <cstdio>
#include <fcntl.h>
#include <cstring>
#include <stdlib.h>
#include <cerrno>
#include <unistd.h>
int main() {
int pipefd[2];
enum {
STDOUT_TERM = 0,
STDIN_TERM = 1
};
if (pipe(pipefd) == -1) { //make a pipe
perror("pipe");
return 0;
}
pid_t pid = fork();
if (pid == 0)
{// Child
dup2(pipefd[STDIN_TERM], STDIN_FILENO);
dup2(pipefd[STDOUT_TERM], STDOUT_FILENO);
dup2(pipefd[STDOUT_TERM], STDERR_FILENO);
execl("/bin/sh","sh", (char*)NULL);
// Nothing below this line should be executed by child process. If so, print err
perror("For creating a shell process");
exit(1);
}
__asm("int3");
puts("Child launched");
}
디버거에서 중단점이 있는 줄에서 시작할 때(전화 이상 puts()
)저것 좀 봐(이거PID변수를 사용하고 ps를 사용하여 해당 프로세스를 보면 매번 다음과 같은 결과가 나타납니다.
2794 pts/10 00:00:00 sh <defunct>
즉, 좀비다
답변1
wait
당신은 자식 프로세스에 있지 않기 때문에 사소한 일이지만 좀비를 남겨두고 있습니다 .
무의미한 방식으로 STDIN을 설정했기 때문에 쉘이 즉시 종료됩니다. pipe
단방향 통신 채널을 반환합니다. 도착 write
하면 에서 돌아 pipefd[1]
옵니다 . 셸이 파이프(STDIN)의 쓰기 측에서 읽기를 시도하도록 하는 일련의 호출을 수행합니다 .read
pipefd[0]
dup2
열거형의 숫자를 바꾸면 쉘이 영원히 멈추게 됩니다 read
. 이것은 아마도 당신이 원하는 것이 아닐 수도 있지만 파이프를 통해 쉘이 자체적으로 연결되어 있을 때 기대할 수 있는 전부입니다.
상위 프로세스에서 쉘을 사용하려고 한다고 가정하면 이를 두 번 호출해야 합니다 pipe
(부모 프로세스에서 둘 다). 사용자가 쓰는 파이프 중 하나(쉘은 stdin에서 읽음)와 쉘이 쓰는 다른 파이프 (stdout /stderr) 그리고 그것을 읽습니다. 또는 원하는 경우 socketpair
.
답변2
SIGCHLD 신호를 포착하고 wait()
시스템 호출을 통해 좀비 프로세스를 "수집"해야 합니다. 신호 처리 기능을 추가하고 이를 SIGCHLD 핸들러로 설정하기 위해 프로그램에 추가하는 것은 다음과 같이 거의 최소한의 코드입니다.
#include <cstdio>
#include <fcntl.h>
#include <cstring>
#include <stdlib.h>
#include <cerrno>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
void sighandler(int signal_number);
void sighandler(int signo) {
if (signo == SIGCHLD) {
int status;
(void)wait(&status);
}
}
int main() {
int pipefd[2];
enum {
STDOUT_TERM = 0,
STDIN_TERM = 1
};
signal(SIGCHLD, sighandler);
pid_t pid = fork();
시스템 호출의 반환 상태를 거의 확실하게 확인 signal()
하고 하위 프로세스의 종료 상태( status
신호 처리기 코드의 값) 처리를 고려해야 합니다.