#!/usr/bin/env bash
sleep 3 && echo '123' &
sleep 3 && echo '456' &
sleep 3 && echo '999' &
이를 실행하고 SIGINT
control-c를 눌러 터미널을 통해 전송하면 여전히 출력이 에코되는 것 같습니다 123...
. 어떻게 든 분리 되었기 때문이라고 생각합니까?
wait < <(jobs -p)
그러나 스크립트 끝에 추가(모든 백그라운드 작업이 완료될 때까지 대기)한 다음 실행하고 보내면 SIGINT
출력 123...
은 다음과 같습니다 .아니요보여주다.
이 행동을 어떻게 설명해야 할까요? wait
신호를 가로채서 백그라운드 프로세스에 전달하는 방법이 있나요 ? 아니면 프로세스가 터미널에 "연결"되어 있는지 여부와 관련된 상태입니까?
이와 관련이 있을 수 있는 질문을 찾았지만 이것이 위의 동작과 어떻게 관련되는지 알 수 없습니다.wait() 함수를 사용할 때 SIGCHLD 신호가 무시되지 않는 이유는 무엇입니까?
답변1
신호 차단? 확산? 아니요
wait
신호를 가로채지 않습니다. 쉘은 그것을 통과하지 못할 것입니다. 신호는 가로채거나 전파되지 않습니다. 세 개의 "백그라운드" 명령으로 구성된 하위 쉘을 실행하거나 신호를 받습니다.곧장아니면.
다음 스크립트를 사용하여 테스트할 수 있습니다.
#!/usr/bin/env bash
printf 'My PID is %s.\n' "$$"
sleep 15 && echo '123' &
sleep 15 && echo '456' &
sleep 15 && echo '999' &
wait < <(jobs -p)
스크립트는 와 같이 동작합니다 wait
. 종료할 수 있다는 의미입니다.그리고Ctrl+ 를 사용하는 세 가지 "백그라운드" 작업 C.
Ctrl+를 클릭하지 않고 다시 실행하십시오 C. 스크립트는 자체 PID( $$
)를 알려줍니다. 이제 SIGINT
다른 터미널( kill -s INT <pid_here>
)에서 전송하면 스크립트가 종료되지만아니요세 가지 직업.
SIGINT
그러나 전체 프로세스 그룹( )에 보내면 kill -s INT -- -<pid_here>
스크립트가그리고일이 그것을 얻을 것입니다. Ctrl+를 누르고 터미널이 키 입력(보통 include ) C에 대해 인터럽트 신호를 보내도록 설정된 경우에도 동일한 일이 발생합니다 .stty -a
intr = ^C
그룹 전체신호를 받습니다.
누가 신호를 받나요?
전경 프로세스 그룹에 관한 것입니다. 쉘이 수행하는 작업 중 하나는 어떤 프로세스 그룹이 포그라운드에 있는지 터미널에 알리는 것입니다.
터미널에는 이와 관련된 전경 프로세스 그룹이 있을 수 있습니다. 이 전경 프로세스 그룹은 신호를 처리하여 입력 문자 [...]를 생성하는 데 특별한 역할을 합니다.
작업 제어를 지원하는 명령 해석기 프로세스는 관련 프로세스를 단일 프로세스 그룹에 배치하고 해당 프로세스 그룹을 터미널과 연결함으로써 터미널을 다른 작업이나 프로세스 그룹에 할당할 수 있습니다. […]
(원천)
귀하의 경우 실제로 일어나는 일은 다음과 같습니다.
- 처음에는 대화형 셸에 있습니다. 쉘은 자체 프로세스 그룹의 리더입니다(프로세스 그룹 ID는 쉘의 PID와 동일합니다). 터미널은 이 프로세스 그룹을 전경 프로세스 그룹으로 인식합니다.
- 위의 셸에는 작업 제어가 활성화되어 있습니다. (일반적으로 작업 제어를 지원하는 쉘은 대화형으로 실행될 때 기본적으로 이를 활성화합니다.) 스크립트(또는 기본적으로 내장되지 않은 스크립트)를 시작하면 쉘은 해당 스크립트를 다른 프로세스 그룹의 리더로 만듭니다. 터미널에는 이제 새로운 프로세스 그룹이 전경 프로세스 그룹으로 간주되어야 한다는 알림이 전달됩니다. 대화형 셸은 이런 방식으로 백그라운드에 배치됩니다.
- shebang에서 우리는 그것이
bash
대본을 해석하고 있다는 것을 알고 있습니다. 비대화형 Bash는 기본적으로 작업 제어가 비활성화된 상태로 시작됩니다. 실행할 명령아니요자체 프로세스 그룹의 리더가 됩니다(명령 자체가 프로세스 그룹을 변경하지 않는 한, 이는 가능하지만 귀하의 경우에는 발생하지 않습니다). 이 세 개의 하위 쉘과 세 개의sleep
프로세스는 실행 중인 스크립트와 동일한 프로세스 그룹에 속합니다. - 스크립트가 종료되면 대화형 셸의 프로세스 그룹이 이제 (다시) 전경 프로세스 그룹으로 간주되어야 한다는 알림이 터미널에 전달됩니다. 스크립트 프로세스 그룹의 프로세스가 여전히 실행 중인 경우 해당 프로세스는 더 이상 포그라운드 프로세스 그룹에 속하지 않습니다.
이는 관찰된 동작을 설명합니다.
Ctrl+를 눌렀을 때 스크립트가 실행 중이면 C스크립트와 기본적으로 모든 하위 항목이 이를 수신합니다
SIGINT
. 스크립트는wait
무언가가 발생하지 않기 때문에 기다립니다&
. 중요한 것은 해당 프로세스 그룹이 여전히 포그라운드 프로세스 그룹이고 (손자)입니다. ) 하위 프로세스가 이 그룹에 속합니다.Ctrl+를 클릭했을 때 스크립트가 더 이상 실행되지 않으면 C해당 하위 항목(있는 경우)은
SIGINT
속하지 않기 때문에 해당 스크립트를 받을 수 없습니다.현재의포그라운드 프로세스 그룹.
작업 제어를 가지고 놀아보세요
작업 제어를 비활성화하거나 활성화하여 이 동작을 변경할 수 있습니다.
작업 제어( )를 비활성화하고 대화형 셸에서 스크립트를 실행하면 set +m
셸은 스크립트를 실행하지만 해당 스크립트를 프로세스 그룹의 리더로 만들지는 않습니다. 스크립트에는 작업 제어가 없습니다. 이 스크립트와 모든 첨자는 기본적으로 대화형 셸의 프로세스 그룹에 속합니다. 이 그룹은 항상 포그라운드 프로세스 그룹이 됩니다. Ctrl+이후에는 스크립트가 계속 실행 중인지 여부에 관계없이 C모든 프로세스(대화형 쉘 포함)가 이를 수신합니다 .SIGINT
set -m
스크립트 자체에서 작업 제어( )를 활성화하면 세 개의 하위 쉘이 자체 프로세스 그룹에 배치됩니다. 유사한 상황에서, 없는 명령은 &
프로세스 그룹 리더가 되고 터미널은 새로운 포그라운드 프로세스 그룹에 대한 정보를 받게 됩니다. 그러나 당신의 명령은 &
그들이 리더가 될 것이지만 전경 프로세스 그룹은 변하지 않을 것이라는 것입니다. Ctrl+, 스크립트가 여전히 실행 중인지 또는 대화형 쉘에 작업 제어가 활성화되어 있는지 여부에 관계없이 C이를 수신하지 않습니다.SIGINT
노트
구분 기호나 종료 기호의 의미는
&
종종 "백그라운드에서 실행 중"이라고 설명되지만 "포그라운드 프로세스 그룹에서 실행되지 않음"과는 다릅니다. 실행 중인 명령은&
포그라운드 프로세스 그룹에 남아 있을 수 있습니다(예: 작업 제어가 비활성화된 경우). 실행되지 않는 명령은&
포그라운드 프로세스 그룹을 떠날 수 있습니다. 확실한 것은&
"비동기적으로 실행"된다는 것입니다.대화형 쉘 배치가 가능하다는 사실에 놀랄 수도 있습니다.그 자체명령을 실행할 때 백그라운드에서 실행됩니다. 이런 일이 발생합니다. 대화형 Bash에서 다음 명령을 실행하세요.
set -m trap 'echo "Signal received."' INT sleep 999
Ctrl+C
sleep
중단된 것을 볼 수 있지만 쉘은 신호를 수신하지 않습니다. 이는 키 입력이 이루어질 때 쉘이sleep
전경 프로세스 그룹인 별도의 프로세스 그룹에 넣기 때문입니다. 쉘은 (then) 포그라운드 프로세스 그룹에 있지 않습니다. 이는 백그라운드에 있다는 것을 의미합니다.이제
set -m
다음으로 변경set +m
하고 다시 실행하세요.set +m trap 'echo "Signal received."' INT sleep 999
Ctrl+C
작업 제어가 비활성화되면
sleep
셸의 프로세스 그룹에서 실행됩니다. 이 그룹은 항상 포그라운드 프로세스 그룹이 됩니다. 에서 보낸 메시지가 표시됩니다trap
.