포크 프로세스가 종료된 후 bash 표시기 프롬프트가 표시되지 않습니다.

포크 프로세스가 종료된 후 bash 표시기 프롬프트가 표시되지 않습니다.

나는 책을 읽고 있습니다Unix 환경의 고급 프로그래밍. 이 기능을 테스트하는 테스트 프로그램이 있습니다 fork. 내 우분투에서는 잘 작동합니다. 그러나 나를 혼란스럽게 하는 것은 하위 프로세스가 종료된 후 명령 표시 프롬프트가 없는 이유입니다. 원본 프로그램은 아래와 같습니다.

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
  pid_t pid;
  if ((pid = fork()) < 0)
  {
    printf("fork error.\n");
    return 1;
  }
  else if (pid == 0)
  {
    if ((pid = fork()) < 0)
    {
      printf("fork error.\n");
      return 1;
    }
    else if (pid > 0)
    {
      printf("first child %d exit.\n", getpid());
      exit(0);
    }
    sleep(2);
    printf("second child %d has parent pid = %d.\n",getpid(),  getppid());
    exit(0);
  }

  printf("waitid %d.\n", pid);
  if (waitpid(pid, NULL, 0) != pid)
  {
    printf("waitid error.\n");
    return 1;
  }
  printf("process %d will exit..\n", getpid());

  exit(0);
}

그럼 난 달려

jerryli@ubuntu:~/project/unix$ ./p183.o
waitid 2256
first child 2256 exit.
process 2255 will exit..
jerryli@ubuntu:~/project/unix$ second child 2257 has parent pid = 1.

위의 줄이 표시된 후에는 아무 것도 계속되지 않습니다. 보여주길 바라요

jerryli@ubuntu:~/project/unix$

위의 측정항목을 얻으려면 를 입력해야 합니다 Enter.

이유를 알 수 있나요? 두 번째 자식 프로세스의 부모 프로세스가 시스템 초기화 프로세스가 되었기 때문일까요?

답변1

fork백그라운드에서 프로세스를 시작합니다. 포그라운드 프로세스(호출 프로세스 fork)가 종료되면 호출 셸에 알리고 새 프롬프트가 표시됩니다. 쉘은 원래 포그라운드 프로세스의 상위이며 분기된 프로세스의 상위가 아닙니다.

원본 프로세스와 분기 프로세스의 실행 순서는 고정되어 있지 않지만 2초의 지연으로 인해 관련 편차가 발생할 가능성은 거의 없습니다. 테스트에서 타임라인은 다음과 같습니다.

  1. fork원래 프로세스의 첫 번째 하위 프로세스입니다.
  2. fork첫째 아이의 둘째 아이.
  3. 원래 프로세스는 waitid추적을 인쇄하고 waitpid첫 번째 하위 프로세스를 기다리기 위해 호출을 시작합니다.
  4. 첫 번째 하위 프로세스는 exit추적을 인쇄한 다음 종료됩니다.
  5. 원래 프로세스에 하위 프로세스가 종료되었음을 알리고 해당 waitpid호출이 반환됩니다.
  6. 원래 프로세스는 will exit추적을 인쇄합니다.
  7. 쉘은 원래 프로세스가 종료되었음을 알리고 프롬프트를 인쇄합니다.
  8. 2초 이내에 sleep두 번째 하위 항목의 호출이 완료되고 두 번째 하위 항목이 해당 has parent추적을 인쇄합니다.

쉘은 종료 프로세스의 상위 프로세스가 아니기 때문에 마지막 이벤트에 대한 알림을 받지 않습니다. 그럼에도 불구하고 이미 새 명령을 입력하기를 기다리는 프롬프트가 표시되고 있습니다. 아무 것도 할 이유가 없습니다(명령을 입력하는 경우 방해가 될 수 있음).

답변2

@Gilles의 답변에 따라 @jerry가 요청한 것과 유사한 것을 구현할 계획입니다. 1. 포크하기 전에 터미널 PID를 저장합니다. 2. 각 인쇄 세트 후에 SIGINT를 보내 터미널을 "푸시"하여 프롬프트를 표시합니다.

매우 더럽지만 작업을 완료한 것 같습니다.

관련 정보