부인 성명:이 문제는 예상보다 훨씬 오래 걸렸습니다. 5개의 하위 질문으로 나누었습니다. 책을 열기 전에 생각을 정리하려고 노력했지만, 지금은 헷갈리는 부분이 너무 많습니다.
내 생각을 명확히 해보는 건 어때요?바르게Bash에서 처리단단한 길, 우연히 발견한Greg의 위키 기사. 처음부터가 아니라 이런 문구가 있네요
무언가를 하려는 하위 프로세스를 시작하는 상위 프로세스에 아직 있는 경우 이는 완벽합니다. 아래 설명된 이유로 PID가 하위 프로세스(죽거나 살아 있음)임을 보장할 수 있습니다. 이를 사용
kill
하여 신호를 보내거나 종료하거나 아직 실행 중인지 확인할 수 있습니다. 이를 사용하여wait
종료될 때까지 기다리거나 종료된 경우 종료 코드를 얻을 수 있습니다.
위에서 언급한 페이지 마지막에이유는 아래에 설명되어 있습니다찾을 수 있습니다.
각 UNIX 프로세스에는상위 프로세스. 상위 프로세스는 자신을 시작한 프로세스이지만
init
새 프로세스가 끝나기 전에 상위 프로세스가 끝나면 해당 프로세스로 변경될 수 있습니다. (즉,init
고아 프로세스가 선택됩니다.) 이 상위/하위 관계를 이해하는 것은 UNIX에서 안정적인 프로세스 관리의 핵심이기 때문에 중요합니다. 프로세스가 종료된 후, 프로세스의 PID는 상위 프로세스wait
가 종료되었는지 확인하고 종료 코드를 검색하기 위해 PID를 얻을 때까지 사용을 위해 해제되지 않습니다. 상위 프로세스가 종료되면 프로세스가 상위 프로세스로 돌아가서init
이 작업을 수행합니다.이는 한 가지 주된 이유로 중요합니다. 상위 프로세스가 하위 프로세스를 관리하는 경우 하위 프로세스가 종료되더라도 상위 프로세스가 작업을 완료할 때까지 다른 새 프로세스가 실수로 하위 프로세스의 PID를 재활용하지 않을 것이라는 점을 절대적으로 확신할 수 있습니다
wait
. PID를 확인하고 아이가 죽은 것을 발견했습니다. 이는 활성 프로세스인지 "좀비" 프로세스인지에 관계없이 하위 프로세스의 PID가 항상 하위 프로세스를 가리킨다는 것을 상위 프로세스에 보장합니다. 다른 사람들은 그런 보장을 받지 못합니다.안타깝게도, 이 보장은 쉘 스크립트에는 적용되지 않습니다. 쉘은 하위 프로세스를 적극적으로 획득하고 스크립트가 호출하는 메모리에 종료 상태를 저장합니다
wait
. 그러나 하위 프로세스는 이미 수집되었습니다.앞으로에 전화하면wait
PID를 보유한 좀비가 없습니다. 커널은 PID를 자유롭게 재사용할 수 있으며 보증이 위반되었습니다.
나는 위의 단락을 여러 번 읽었지만 여전히 그 뒤에 숨겨진 메시지를 올바르게 이해하고 있는지 확신할 수 없습니다.
질문 1:두 번째 긴 인용문, 특히 마지막 인용문에서 저는 쉘(Bash에만 관심이 있습니다) 스크립트에서 변수에 저장한 PID가 여전히 백그라운드 프로세스를 참조하는지 100% 확신할 수 없다고 결론을 내렸습니다. 시작했습니다. 다른 프로세스(자식 프로세스도 아님)에 대해 커널에서 재사용할 수 있기 때문입니다. 이 올바른지? 위의 보증은 시스템의 어느 부분에 적용됩니까?
질문 2:두 번째 인용문의 마지막 문단이 첫 번째 인용문과 모순되는 것으로 보입니다. 전체적으로 사실인가요?쉘 스크립트에서저것"아직 하위 프로세스를 시작한 상위 프로세스에 있는 경우 [...] PID가 하위 프로세스(죽거나 살아 있음)임을 보장할 수 있습니다."?
질문 3:웹에서 해당 주제에 대한 다른 출처를 찾아보았으나 언제나 그렇듯 사실과 부정확한 진술을 구별하기는 어렵습니다. 몇 가지 확인을 받았지만 더 많은 질문도 있습니다. 인용하다이것그리고이것문제는 백그라운드에서 스크립트로 프로세스를 시작하고, PID를 변수에 저장하고, 어떤 작업을 수행한 다음 PID를 조합하여 wait
종료 코드를 얻거나 kill
신호를 보내는 순진한 접근 방식이 실패할 수 있다는 것입니다. PID는 커널에서 재사용됩니다. 보편적인 요리법이 있나요?
질문 4:나도 찾았어이 댓글이는 "백그라운드(프로세스)가 반환 코드를 파일에 저장하고 상위 프로세스가 파일에서 가져오도록 합니다"를 의미합니다. 이것이 믿을만한 방법인가?
질문 5:사용시 주의사항이 있나요 wait -n
? PID를 명시적으로 제공하지 않으면(재사용 가능) wait
오류가 발생하지 않을 것이라고 생각합니다. 하지만,것 같다Bash v4.4에서는 작업 제어를 활성화할 때 -n
이 옵션이 wait
유용했습니다. set -m
Bash v5.0에서도 마찬가지입니까?
보너스 질문: 이 답변내용은 Greg의 위키와 유사합니다.
pid를 사용하여 신호를 보내는 것이 안전한 경우는 단 하나뿐입니다. 대상 프로세스가 신호를 보낼 프로세스의 직접적인 하위 프로세스이고 상위 프로세스가 아직 신호를 기다리고 있지 않은 경우입니다.
무엇인가요직접어린이? 어린아이와는 좀 다른가요?
답변1
...셸(Bash에만 관심이 있음) 스크립트에서 변수에 저장된 PID가 내가 시작한 백그라운드 프로세스를 계속 참조하는지 100% 확신할 수 없습니다. 다른 프로세스. ..
옳은.
쉘이 프로그래밍된 방식에 따라 쉘은 wait()
하위 프로세스가 종료되자마자 이를 호출하여(종료 상태를 내부 상태의 일부로 저장) 다른 프로세스에서 재사용할 수 있도록 PID를 해제합니다.
이것이 쉘 스크립트의 경우입니까?"아직 하위 프로세스를 시작한 상위 프로세스에 있는 경우 [...] PID가 하위 프로세스(죽거나 살아 있음)임을 보장할 수 있습니다."?
아니요, 이는 사실이 아닙니다.
앞서 언급한 것처럼(및 인용문에서) 쉘 자체가 하위 프로세스를 즉시 수집하므로 기본적으로 이 보장이 깨집니다.
백그라운드에서 스크립트로 프로세스를 시작하고, 해당 PID를 변수에 저장하고, 몇 가지 작업을 수행한 다음 대기와 함께 PID를 사용하여 종료 코드를 얻거나 Kill을 사용하여 신호를 보냅니다. 이 간단한 접근 방식은 중복될 수 있습니다. 실패한 PID 사용 핵심.
쉘을 사용하면 이것이 최선입니다.
using은 wait
실제로 문제가 되지 않습니다. 단지 kill
자식 프로세스가 죽었을 수도 있고, PID가 재사용되었으며, 다른 프로세스를 죽이고 있기 때문일 뿐입니다.
wait
그 자체는 쉘에서 구현됩니다. 하위 프로세스를 획득하면 해당 종료 상태를 메모리에 저장하므로 wait
해당 정보를 내장 기능에 사용할 수 있습니다(아직 실행 중인 하위 프로세스를 기다리는 것도 포함).
또한 커널은 일반적으로 PID 재사용을 피하려고 시도하며, 최소한 PID 재사용을 지연하려고 시도합니다. 이는 정확히 어떤 경우에는 PID가 재사용되지 않을 것이라는 보장이 없기 때문입니다. 따라서 커널은 이러한 상황을 최소화하려고 시도합니다. 신호가 잘못된 프로세스로 전달됩니다.
보편적인 요리법이 있나요?
신뢰성을 위해서?
예, C 또는 Python, Perl, Ruby 등을 사용하여 백그라운드 프로세스를 시작하는 코드를 구현합니다. 쉘이 아닌.
기본적으로 쉘처럼 자식을 가져오지 않기 때문에 이 문제가 없습니다. 따라서 명시적으로 이를 수행해야 합니다.
또는 시스템 관리자(예: systemd)를 사용하여 백그라운드 프로세스를 시작하는 것을 고려해보세요.
"백그라운드(프로세스)가 반환 코드를 파일에 저장하고 상위 프로세스가 파일에서 가져오도록 합니다." 이것이 믿을만한 방법인가?
아마도.
거기에 간섭이 없다고 보장할 수는 없습니다. 해당 프로세스만 쓸 수 있고 다른 프로세스는 쓸 수 없는 위치를 찾는 것이 어렵습니다.
이는 호출의 경우에는 해당되지 않으며 wait
커널은 다른 프로세스에 의해 위조될 수 없도록 보장합니다.
또한 wait
호출을 통해 프로세스가 종료되었거나 심지어 충돌했음을 알려줄 수도 있습니다. 이 경우 반환 상태를 파일에 기록하는 프로세스 자체에 의존했다면 불완전한 정보를 얻을 수 있습니다.
또한 PID 재사용의 주요 문제는 PID를 죽이는 것입니다. 이는 반환 코드를 가져오면 실제로 문제가 되지 않으며 파일을 사용하여 반환 코드를 저장해도 wait
문제가 실제로 해결되지 않습니다.kill
사용시 주의사항이 있나요
wait -n
?
설마. wait
AFAICT는 신뢰할 수 있고 PID 재사용의 영향을 받지 않습니다. 쉘이 하위 프로세스를 획득할 때 사용 중인 PID 및 반환 코드를 포함한 해당 정보를 내부 상태의 일부로 유지하기 때문입니다.
에 전화하시면 wait
이 양식을 통해 정보를 얻으실 수 있습니다.
첫 번째 인스턴스가 호출되기 전에 동일한 셸의 새로운 백그라운드 하위 프로세스에서 PID를 재사용하면 잠재적인 문제가 있을 수 있다고 생각합니다. wait
그 시점부터 테이블에 충돌이 발생하고 두 개의 별도 개체로 끝날 것입니다. 동일한 PID를 가진 백그라운드 프로세스. 이것은 극단적인 경우입니다. 매우 드물다고 생각하지만 실제일 수도 있습니다. 이 경우 쉘이 무엇을 하는지는 잘 모르겠습니다. 쉘 구현에 따라 달라질 수 있으며 버전마다 다를 수 있습니다.
그러나 앞서 언급했듯이 이 문제에 대한 실제 해결책은 PID에 대한 보장을 유지하는 것이며 이러한 보장이 중요할 경우 셸이 아닌 다른 것을 사용하는 것입니다.
무엇인가요직접어린이? 어린아이와는 좀 다른가요?
마치 어린아이처럼.
이것은 당신 자신의 갈래 자식입니다.
예를 들어 하위 프로세스가 프로세스를 분기하고 해당 프로세스의 PID를 전달하는 경우 해당 프로세스가 지속된다는 보장이 더 이상 없습니다.
이 프로세스를 수집하는 것이 자녀의 임무이므로 자녀는 PID를 수집할 때까지 PID가 재사용되지 않도록 할 수 있습니다. 그것은 당신 것이 아닙니다.
물론, 상위 프로세스는 하위 프로세스와 협력하여 이 보장을 확장할 수 있습니다. 예를 들어 하위 프로세스 PID를 쿼리하여 여전히 예상되는 프로세스인지 확인한 다음 하위 프로세스를 수집하는 것을 방지하고 신호를 보냅니다. , 또는 아마도 어린이에게 요청하여(보증하는 사람과 함께) 부모를 대신하여 신호를 보냅니다.
이것이 문제 해결에 도움이 되기를 바랍니다.