2012-10-08 4 views
0

나는 잠시 후 다시 죽여야 만하는 프로세스를 프로그래밍 방식으로 생성하기 위해 popen2 (stackoverflow의 다른 곳에서 권장되는) 함수를 사용하고 있습니다. popen2는 PID를 반환하고이 PID를 사용하여 프로세스를 종료 할 수 있다고 생각했습니다. 하지만이 방법으로는 작동하지 않습니다. 그것을 죽이려면 반환 된 PID를 증가시켜야하는데 이해할 수 없습니다 (아래 코드 참조)popen2로 만든 살인 프로세스

다양한 스레드가 병렬로이를 수행 할 때 또 다른 문제가 발생할 수 있습니다. 이 경우 경쟁 조건으로 인해 PID가 둘 이상 다를 수 있다고 생각합니다.

내 질문은 : 어떻게 안정적으로 멀티 스레드 시나리오에서 popen2에 의해 만들어진 프로세스의 PID를 식별 할 수 있습니까?

#include <sys/types.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <signal.h> 

#define READ 0 
#define WRITE 1 

pid_t popen2(const char *command, int *infp, int *outfp) { 

    int p_stdin[2], p_stdout[2]; 
    pid_t pid; 

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) 
     return -1; 

    pid = fork(); 

    if (pid < 0) 
     return pid; 
    else if (pid == 0) 
    { 
     close(p_stdin[WRITE]); 
     dup2(p_stdin[READ], READ); 
     close(p_stdout[READ]); 
     dup2(p_stdout[WRITE], WRITE); 

     execl("/bin/sh", "sh", "-c", command, NULL); 
     perror("execl"); 
     exit(1); 
    } 

    if (infp == NULL) 
     close(p_stdin[WRITE]); 
    else 
     *infp = p_stdin[WRITE]; 

    if (outfp == NULL) 
     close(p_stdout[READ]); 
    else 
     *outfp = p_stdout[READ]; 

    return pid; 
} 

main() { 
    pid_t pid; 

    // Create process 
    pid = popen2("crafty", &in, &out); 

    sleep(5); 

    // Why doesn't kill(pid, SIGKILL) work? 
    kill(pid+1, SIGKILL); 

    while (1); 
} 
+0

실제로 popen2가 유효한 PID를 반환합니까? '-1'을 반환하면 오류를 나타낼 수 있습니다. '-1'에서'kill '을 호출하면 시스템 전체를 죽이려고 시도 할 수도 있고 그렇지 않을 수도 있습니다. 반대로'0'에서'kill'은 프로세스 그룹을 죽일 것입니다 : 프로세스와 그것의 자식들입니다. –

+0

예, 반환 된 PID가 유효한지 확실합니다. – chessweb

답변

6

나는 그것을 얻었습니다.

execl("/bin/sh", "sh", "-c", command, NULL); 

실행 sh하고 PID의 popen2 돌아갑니다. kill에 전화하면 sh이 (가) 만료되지만 하위 프로세스 인 command에는 건드리지 않습니다. 그것은 실제로 다음 pid를 죽이는 우연히 command를 죽입니다. 이것은 항상 작동하지 않고 경주 조건에 달려 있습니다.

목표 프로세스를 종료하려면 직접 시작해야합니다.

경고 (테스트되지 않은 코드) :

pid_t popen2(const char **command, int *infp, int *outfp) { 

    int p_stdin[2], p_stdout[2]; 
    pid_t pid; 

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) 
     return -1; 

    pid = fork(); 

    if (pid < 0) 
     return pid; 
    else if (pid == 0) 
    { 
     close(p_stdin[WRITE]); 
     dup2(p_stdin[READ], READ); 
     close(p_stdout[READ]); 
     dup2(p_stdout[WRITE], WRITE); 

     execvp(*command, command); 
     perror("execvp"); 
     exit(1); 
    } 

    if (infp == NULL) 
     close(p_stdin[WRITE]); 
    else 
     *infp = p_stdin[WRITE]; 

    if (outfp == NULL) 
     close(p_stdout[READ]); 
    else 
     *outfp = p_stdout[READ]; 

    return pid; 
} 

및 특정 예에서

char *command[] = {"program", "arg1", "arg2", ..., NULL}; 

의 형태로 명령을 전달합니다

char *command[] = {"crafty", NULL}; 
+0

그건 다소 도움이됩니다. 그것은 의도대로 작동하지만 반환 된 PID로 프로세스를 종료하고 ps aux | grep 교활한 셸에서 프로세스가 계속 실행되고 있음을 알 수 있습니다. 그러나 입니다. 프로그램 자체가 종료 될 때까지 사라지지 않습니다. – chessweb

+2

죽은 프로세스가 부모 프로세스에 의해 수집/정리되어야하기 때문입니다. 자식 프로세스가 죽으면 좀비가되고'ps'는'Z'와' '이라고 표시합니다. 죽어가는 프로세스는 부모에게'SIGCHLD' 신호를 보내고'wait' 계열의 시스템 호출로 수집 할 수 있습니다. 쉘은 자동으로 그렇게하며 사용자 프로그램은 그렇지 않습니다. 간단한 해결책은 살해 후에'wait (0);을 호출하는 것입니다 (주의 : 아이가 어떤 이유로 든 죽지 않는다면 영원히 기다릴 것입니다). 좀비 프로세스에 대한 자세한 내용은 http://en.wikipedia.org/wiki/Zombie_process를 참조하십시오. –

1

당신이 사용할 수있는 '간부'명령 보류중인 프로세스를 피하기위한 쉘. 또한 popen2는 사용하지 않은 파이프의 쓰기 끝을 닫아야합니다. 그렇지 않으면 파이프가 열려 있습니다. 포인터 (infp, outpf) 중 하나가 NULL이면 파이프를 만들고 즉시 닫는 것은 쓸모가 없습니다. 다음은 프로젝트에서 사용하는 popen2 버전입니다.

pid_t popen2(char *command, int *in_fd, int *out_fd) { 
    int  pin[2], pout[2]; 
    pid_t pid; 
    char cmd[strlen(command)+10]; 

    if (out_fd != NULL) { 
     if (pipe(pin) != 0) return(-1); 
    } 
    if (in_fd != NULL) { 
     if (pipe(pout) != 0) { 
      if (out_fd != NULL) { 
       close(pin[0]); 
       close(pin[1]); 
      } 
      return(-1); 
     } 
    } 

    pid = fork(); 

    if (pid < 0) { 
     if (out_fd != NULL) { 
      close(pin[0]); 
      close(pin[1]); 
     } 
     if (in_fd != NULL) { 
      close(pout[0]); 
      close(pout[1]); 
     } 
     return pid; 
    } 
    if (pid==0) { 
     if (out_fd != NULL) { 
      close(pin[1]); 
      dup2(pin[0], 0); 
     } 
     if (in_fd != NULL) { 
      close(pout[0]); 
      dup2(pout[1], 1); 
     } 
     // Exec makes possible to kill this process 
     sprintf(cmd, "exec %s", command); 
     execlp("sh", "sh", "-c", cmd, NULL); 
     fprintf(stderr, "%s:%d: Exec failed in popen2. ", __FILE__, __LINE__); 
     perror("Error:"); 
     exit(1); 
    } 
    if (in_fd != NULL) { 
     close(pout[1]); 
     *in_fd = pout[0]; 
    } 
    if (out_fd != NULL) { 
     close(pin[0]); 
     *out_fd = pin[1]; 
    } 
    return pid; 
}