내 고아 손자는 왜 출산 후에야 죽었는가?

내 고아 손자는 왜 출산 후에야 죽었는가?

나는 동시에 실행되는 일련의 하위 프로세스 "슬레이브"를 관리하는 프로그램 "마스터"를 보고 있습니다. 하위 프로세스는 필요에 따라 시작되고 종료됩니다. 이러한 하위 프로세스 중 다수는 시작 스크립트를 사용합니다.

출력은 pstree다음과 같습니다(발췌, 마스터는 Java로 구현되고 두 개의 슬레이브는 스크립트를 통해 시작됨).

systemd───java─┬─sh───slave
               ├─slave
               └─sh───slave

이전에는 시작 스크립트가 사이트의 출력을 로그 파일로 리디렉션했습니다. 마스터 장치가 슬레이브 장치의 출력도 처리해야 하는지 결정합니다. 다음과 같이 버퍼링된 판독기를 추가하여 마스터 구현을 확장합니다.

process =  Runtime.getRuntime().exec(cmd);
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
while (null != (line = br.readLine())) {
    // handle slave output here
}

그런 다음 시스템은 SIGTERM마스터에 의해 종료(전송)되었지만 실제로는 여전히 실행 중인 슬레이브에 심각한 문제가 있었습니다. 나는 이런 일이 일어났다는 것을 알아차렸다오직두 가지 기준을 충족하는 슬레이브의 경우:

  • 그들은 시작 스크립트를 사용했습니다
  • 표준 출력에 쓰는 경우는 거의 없습니다.

마스터가 슬레이브를 죽이지 않고 슬레이브의 직계 부모(쉘 해석기)만 죽였기 때문에 이제 슬레이브는 init의 소유가 됩니다. 제 경우에는 systemd가 기본값인 것 같습니다사신. pstree다음과 같습니다.

systemd─┬─java───sh───slave
        └─slave

기능적으로는 명시적으로 문제를 해결했습니다.노예의 가족 전체를 죽여라. 하지만 나는 아직도 알고 싶습니다:

systemd가 stdout(또는 오류)에 쓰고 이전에 다른 프로세스에서 stdout을 읽었을 때 고아 프로세스만 종료하는 이유는 무엇입니까?

이 질문은 실제로 꽤 깁니다. 요청 시 설명된 동작을 재현하기 위한 최소한의 코드 예제를 제공할 수 있습니다.

답변1

systemd에서는 이 작업을 수행할 수 없습니다.

대조적으로, 프로세스가 읽기 측에서 닫힌 파이프에 쓰려고 시도하면 SIGPIPE에 의해 프로세스가 종료됩니다. 이는 "표준 출력이 이전에 다른 프로세스에 의해 읽혀졌습니다"라는 설명과 일치합니다.

관련 정보