문제

나는 몇 가지 과정이 나타납니다 <defunct> 안에 top (그리고 ps). 나는 실제 대본과 프로그램에서 물건을 끓였다.

crontab:

* * * * * /tmp/launcher.sh /tmp/tester.sh

의 내용 launcher.sh (물론 실행 파일로 표시) :

#!/bin/bash
# the real script does a little argument processing here
"$@"

의 내용 tester.sh (물론 실행 파일로 표시) :

#!/bin/bash
sleep 27 & # the real script launches a compiled C program in the background

ps 다음을 보여줍니다.

user       24257 24256  0 18:32 ?        00:00:00 [launcher.sh] <defunct>
user       24259     1  0 18:32 ?        00:00:00 sleep 27

주목하십시오 tester.sh 나타나지 않습니다. 배경 작업을 시작한 후 종료되었습니다.

launcher.sh 주위를 붙잡고 표시합니다 <defunct>? 그것은 시작했을 때만 이것을하는 것 같습니다 cron-내가 직접 실행할 때.

추가 참고 사항 : launcher.sh 이 시스템에서 공통 스크립트로, 쉽게 수정되지 않습니다. 다른 것들 (crontab, tester.sh, 내가 대신 실행하는 프로그램조차도 sleep) 훨씬 더 쉽게 수정할 수 있습니다.

도움이 되었습니까?

해결책

그들은 a의 주제가 아니었기 때문입니다 wait(2) 시스템 호출.

누군가가 미래에 이러한 프로세스를 기다릴 수 있기 때문에 커널은 완전히 제거 할 수 없거나 실행할 수 없습니다. wait 시스템 호출은 출구 상태 나 그 존재의 증거가 더 이상 없기 때문에 통화합니다.

쉘에서 하나를 시작하면 쉘이 Sigchld를 덫을 놓고 다양한 대기 작업을 수행하므로 오랫동안 아무것도 소진되지 않습니다.

그러나 Cron은 대기 상태가 아니며 자고 있으므로 Cron이 깨어날 때까지 소멸 된 어린이는 잠시 동안 고집 할 수 있습니다.


업데이트: 의견에 응답 ... 흠. 문제를 복제 할 수있었습니다.

 PPID   PID  PGID  SESS COMMAND
    1  3562  3562  3562 cron
 3562  1629  3562  3562  \_ cron
 1629  1636  1636  1636      \_ sh <defunct>
    1  1639  1636  1636 sleep

그래서 일어난 일은 다음과 같습니다.

  • Cron Forks와 Cron Child가 쉘을 시작합니다
  • Shell (1636)은 SID 및 PGID 1636을 시작하여 수면을 시작합니다.
  • 쉘 출구, Sigchld가 Cron 3562로 보냈습니다
  • 신호는 무시되거나 잘못 처리됩니다
  • 쉘은 좀비를 바꿉니다. 수면은 초기에 기소되므로 수면 출구가 시작되면 신호를 얻고 청소할 수 있습니다. 나는 여전히 좀비가 거두는시기를 알아 내려고 노력하고 있습니다. 아마도 활동적인 어린이가 없으면 Cron 1629가 종료 될 수 있습니다. 그 시점에서 좀비는 기판이 시작되어 다시 나타납니다. 이제 우리는 Cron이 처리 해야하는 누락 된 sigchld에 대해 궁금합니다.
    • 반드시 Vixie Cron의 잘못은 아닙니다. 여기에서 볼 수 있듯이 Libdaemon은 Sigchld 핸들러를 설치합니다 ~ 동안 daemon_fork(), 그리고 이것은 중간 1629의 빠른 출구에서 신호 전달을 방해 할 수 있습니다.

      지금, 나는 우분투 시스템의 Vixie Cron이 Libdaemon으로 만들어 졌는지조차 모르지만 적어도 새로운 이론이 있습니다. :-)

다른 팁

CRON이 세션의 모든 하위 프로세스가 종료되기를 기다리고 있다고 생각합니다. 부정적인 PID 인수와 관련하여 대기 (2)를 참조하십시오. Sess를 다음과 같이 볼 수 있습니다.

ps faxo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm

다음은 내가 보는 것 (편집)입니다.

STAT  EUID  RUID TT       TPGID  SESS  PGRP  PPID   PID %CPU COMMAND
Ss       0     0 ?           -1  3197  3197     1  3197  0.0 cron
S        0     0 ?           -1  3197  3197  3197 18825  0.0  \_ cron
Zs    1000  1000 ?           -1 18832 18832 18825 18832  0.0      \_ sh <defunct>
S     1000  1000 ?           -1 18832 18832     1 18836  0.0 sleep

SH와 수면은 같은 부분에 있습니다.

setSid (1) 명령을 사용하십시오. 여기 Tester.sh :

#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background

필요하지 않습니다 &, SetSid는 그것을 백그라운드에 넣습니다.

내 생각에, 그것은 Crontab의 명령의 stdout/stderr에 파이프를 입은 stdin의 입력을 기다리는 프로세스 crond (모든 작업에 대해 crond에 의해 생성됨)에 의해 발생합니다. CRON이 메일을 통해 결과 출력을 사용자에게 보낼 수 있기 때문에 수행됩니다.

따라서 Crond는 사용자 명령이있을 때까지 EOF를 기다리고 있으며 모든 어린이 프로세스가 파이프를 닫았습니다. 이 작업이 완료되면 Crond는 대기 경감으로 계속되고 소진 된 사용자 명령이 사라집니다.

따라서 스크립트에서 스폰 된 모든 하위 프로세스를 명시 적으로 분리하여 파이프를 형성합니다 (예 : 파일 또는 /dev /null로 리디렉션하여 파이프를 리디렉션합니다.

따라서 다음 줄은 Crontab에서 작동해야합니다.

* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & ) 

두 가지 별도의 프로세스가 없으면 문제를 해결하는 것이 좋습니다. launcher.sh 마지막 줄 에서이 작업을 수행하십시오.

exec "$@"

이것은 불필요한 과정을 제거합니다.

비슷한 문제가있는 해결책을 찾는 동안이 질문을 찾았습니다. 불행히도이 질문에 대한 답변은 내 문제를 해결하지 못했습니다.

부모 프로세스를 찾아 죽여야하므로 소멸 프로세스를 죽이는 것은 옵션이 아닙니다. 나는 다음과 같은 방식으로 소멸 된 프로세스를 죽였습니다.

ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",$3}' | sh

"grep ''에서는 검색을 특정 소멸 프로세스로 좁힐 수 있습니다.

나는 같은 문제를 여러 번 테스트했습니다. 그리고 마침내 해결책이 있습니다. 아래와 같이 Bash 스크립트 앞에 '/bin/bash'를 지정하면됩니다.

* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top