백그라운드 프로세스 자체가 가능합니까?
Perl 및/또는 C 구현은 무엇입니까?
답변1
나는 여기서 문자 그대로의 질문에 대답하려고 합니다. 할 수 있습니까?프로세스배경그 자체포크 자체와는 반대로 실행은 하위 프로세스에서 계속되고 종료되므로 이를 기다리는 프로세스는 여기에서 이미 다른 프로세스에 의해 처리된 실행을 다시 시작할 수 있습니다.
여기서는 먼저 용어에 대해 설명합니다.
배경은 일반적으로 대화형 셸의 작업 제어를 나타냅니다.
추가 명령을 사용하여 명령을 실행하는 것과 같습니다 &
. 아니면 Ctrl+를 누르고 Z실행하세요 bg
.
일하다프로세스 없음프로세스 그룹. 실행할 때:
$ ps -ej | grep -w "$$" & echo "$!"
35131
19152 19152 19152 pts/0 00:00:00 zsh
35130 35130 19152 pts/0 00:00:00 ps
35131 35130 19152 pts/0 00:00:00 grep
이것은ps | grep
일하다(이는 리더가 실행 중인 프로세스 ps
이지만 실행 중인 프로세스도 포함하는 35130 프로세스 그룹을 통해 달성됩니다 grep
.) 프로세스는 백그라운드에 배치됩니다.
배경여기서 의미하는 바는 다음과 같습니다.
- 셸은 작업이 종료될 때까지 기다리지 않습니다. 프롬프트로 돌아가서 작업이 계속 실행되는 동안 더 많은 명령을 입력할 수 있습니다.
- 터미널 장치 드라이버는 프로세스 그룹이 포그라운드에 있지 않다는 알림을 받았습니다. 따라서 이 프로세스 그룹의 프로세스에는 터미널에서 데이터를 읽을 수 있는 권한이 없으며(그룹의 프로세스 중 하나라도 터미널에서 데이터를 읽으려고 하면 그룹의 모든 프로세스가 중단됨)
^C
//^Z
의 영향을 받지 않습니다^\
. 등. - 쉘은 내부 작업 테이블에 작업을 입력하고 현재 백그라운드에 있는 것으로 기록합니다.
지금배경표현은 때때로 터미널 작업 제어 외부에서 사용됩니다.
이 작업을 수행할 때:
cmd1 | cmd2 & pid=$!
somecommand
wait
스크립트에는 작업 제어가 없습니다. 스크립트가 대화형 셸을 통해 터미널에서 실행되면 다른 명령과 마찬가지로 스크립트 실행 방법에 따라 자체적으로 전경이나 배경으로 이동됩니다.
그러나 cmd1 | cmd2
스크립트를 해석하는 쉘은 대화형 쉘이 아니기 때문에 스크립트의 내용이 백그라운드에 배치되지 않습니다.
^C를 누르면 스크립트를 실행하는 셸이 종료 cmd1
되고 cmd2
^Z를 누르면 일시 중지됩니다. cmd1 | cmd2
백그라운드에서 시작하는 것 보다비동기식으로 실행됩니다..
백그라운드에서 시작된 작업과 비교인터렉티브인클로저, 전용1이미 마쳤어. 파이프를 실행하기 위해 프로세스 그룹이 생성되지 않았습니다.
이제 이 사실이 명확해지면 프로세스가 백그라운드에 배치될 수 있습니까?
그냥 좋아일하다설마프로세스이를 맥락에 맞게 설명하면 이 프로세스에 대한 질문은 다음과 같습니다.
- 나는 터미널에 연결된 세션에 참여하고 있나요? (작업 통제가 의미가 있나요?)
- 나만 그런 걸까요, 아니면 내 프로세스 그룹에 다른 프로세스가 있는 걸까요?
- 내 프로세스 그룹이 이미 포그라운드에 있습니까, 아니면 백그라운드에 있습니까?
- 내 프로세스 그룹이 대화형 셸에서 대기하게 됩니까?
이러한 모든 질문에 "예"라고 답할 수 있다면, 즉 터미널의 대화형 셸에서 간단한 명령(파이프나 복합 명령의 일부가 아닌)으로 호출되는 경우 다음이 필요합니다. (1) Tell 쉘이 우리를 기다리는 것을 멈추는 대기 프로세스, (2) 프로세스 그룹이 더 이상 전경 프로세스 그룹이 아니라는 것을 터미널에 알리고, (3) 우리가 지금 있는 사실을 기록하기 위해 작업 테이블을 업데이트하도록 쉘에 지시합니다. 배경.
종료하거나 정지하는 것 외에 다른 프로세스에게 사용자를 기다리지 말라고 지시할 수는 없습니다. 이 경우 프로세스는 신호를 받거나 정지됩니다 SIGCHLD
.wait*()
호출하면 현재 수행 중인 작업이 무엇이든 반환됩니다.
그러나 SIGTSTP 신호(시간에 전송된 동일한 신호) 또는 SIGSTOP(가로채기 불가능)을 보내 자신을 일시 중지할 수 있습니다 ^Z
. 이 경우 모든 (1), (2) 및 (3)이 자동으로 발생합니다. 상태는정지시키다바꾸다백그라운드에서 실행.
이제 일시 중지되었으므로 더 이상 실행할 수 없으며 다시 시작할 수 없습니다.
그러나 (pid에 SIGCONT를 전송하여) 일시 중단되기 전에 일정 기간 동안 자체적으로 재개되는 하위 프로세스를 포크할 수 있습니다.
실행을 재개하면 쉘은 SIGCHLD를 다시 수신하고 (3) 쉘은 현재 상태를 인식합니다.달리기이는 신호 처리를 시작할 때 백그라운드에서 발생합니다.
예를 들어 다음을 구현하십시오 sh
.
$ sh -c 'echo running in foreground; sleep 1
(sleep 1; echo resuming my parent; kill -s CONT "$$") &
echo stopping; kill -s STOP "$$"
echo resumed
sleep 30
echo finished'; echo "$?"
running in foreground
stopping
147
zsh: suspended (signal) sh -c
$ resuming my parent
resumed
$ jobs
[1] + running sh -c
$ finished
[1] + done sh -c
kill(0, SIGSTOP)
( kill -s STOP 0
in )을 사용하여 전체 작업을 일시 중지하는 것도 가능 sh
하지만, 아직 시작되지 않았고 알려지지 않은 프로세스의 실행 흐름에 영향을 미치기 때문에 프로세스가 그렇게 하는 것이 올바른가요?
sh -c 'echo running in foreground
perl -MPOSIX -le "setpgid 0,0; # leave the process group before it is suspended
sleep 2;
print q(resuming the process group of my parent);
kill q(CONT), - shift@ARGV
" "$(ps -o pgid= -p "$$")" &
sleep 1
echo stopping my process group; kill -s STOP 0
echo process group resumed
sleep 30
echo finished' | cat
답변2
가끔.
- 프로세스는백그라운드에서 실행현재 프로세스 그룹 ID와 다른 프로세스 그룹 ID가 있습니다.포그라운드 프로세스 그룹 ID제어 터미널에서.
- 이것은혼동하지 마세요프로세스는데몬으로 실행, 포그라운드 및 백엔드 개념이 적용되는 모든 로그인 세션을 소모합니다.전혀 해당되지 않음애초에 제어 터미널이 없기 때문이다.
Angel의 답변에 담긴 조언은 구식이고 끔찍합니다. "데몬"이 호출되면 실제로 로그인 세션에서 역할을 수행하지 않습니다. 시스템은 로그인 세션을 설정하기 위해 너무 많은 단방향 트랩도어를 통과합니다. Ángel의 답변은 setlogin()
OpenBSD, AIX의 보호 환경(참고자료 참조), Linux의 보안 컨텍스트 및 제어 그룹과 같은 사항을 무시할 뿐만 아니라 거의 모든 C에 setsenv
대해서도 마찬가지입니다. 도서관의 오래된 도서관 기능 .daemon()
1980년대부터 이 접근 방식은 더 이상 작동하지 않습니다. 왜냐하면 이러한 일방통행 트랩 도어가 1990년대에 많이 등장했기 때문입니다. "악마화"는 불행하게도 수년이 지난 후에도 여전히 받아들여지는 지혜와 민간 전설에 의해 조장되는 오류입니다.
데몬도 아니고~해야 한다하다. 1980년대 후반(예: AT&T Unix Service Access Facility) 및 1990년대(예: IBM의 시스템 리소스 컨트롤러)의 서비스 관리 하위 시스템 호출 데몬이미 데몬 컨텍스트에 있음. 처음에는 로그인 세션 컨텍스트 내에서 시작되지 않습니다.
또한, 서비스 관리 하위 시스템이 30년 넘게 데몬에 사용해 온 제어 의미론과 상위 분기 충돌을 수행하면 서비스 관리 하위 시스템이 데몬에 대해 설정한 로깅 메커니즘과 충돌합니다. .
- 파일 설명자를 닫는 것은 TTY 신호(앞서 언급한 민속의 예)와 아무 관련이 없으며 daemontools에서 systemd, runit에 이르는 서비스 관리 하위 시스템이 로그로 보내기 위해 stdout 및 stderr을 설정하는 방식을 중단시킵니다. 서비스 관리 하위 시스템은 먼저 임의의 파일 설명자를 열어 데몬을 시작하지 않습니다. 반복 가능하고 일관되며 일반적으로 최소한의(달리 명시적으로 구성되지 않은 경우) 열린 파일 설명자 집합을 사용하여 데몬을 시작합니다.
- 상위 프로세스를 분기하고 종료하는 것은 시스템 관리자가 쉘 스크립트에 또는 심지어 수퍼유저 로그인 세션에 데몬을 추가하여 대화식으로 데몬을 시작하고 서비스 관리 하위 시스템의 사용에 반대했던 1980년대의 일입니다.
/etc/rc
ing에서/etc/rc.local
얻은 프로세스 ID는fork()
서비스를 추적하고 제어하기 위한 사실상의 서비스 프로세스입니다. (자세한 내용을 읽으면 알 수 있듯이 IBM은 시스템 리소스 컨트롤러가 존재하는 한 이에 대해 권장해 왔습니다.) 서비스 관리 하위 시스템은 세션에서 데몬을 호출합니다.이미 가지고 있다제어 터미널이 없습니다.
또한 "데몬"은 사람들이 얻는 데 사용되는 것이 아닙니다.로그인 세션의 백그라운드에서. 작업 제어 셸은 tcsetpgrp()
제어 터미널의 현재 상태를 변경하는 함수를 호출하여 로그인 세션의 전경과 배경에 항목을 배치합니다.포그라운드 프로세스 그룹 ID값. 이는 실제로 파일 설명자나 (커널) 세션을 닫는 fork()
것과는 아무 관련이 없습니다.chdir()
쉘 하위 프로세스할 수 있는전화를 걸지만 (a) 다음과 같은 경우 tcsetpgrp()
신호가 전송된다는 점에 유의하세요.SIGTTOU
이미(b) 전환할 다른 프로세스 그룹 ID를 찾는 것은 쉽지 않습니다. 왜냐하면 쉘이 모든 경우에 직접적인 부모가 아닐 수도 있기 때문입니다.
- 백그라운드에서 프로세스를 시작하려면 셸의
&
메커니즘을 사용하세요. - 전경 프로세스 그룹을 배경으로 대화식으로 전환하려면 터미널에서 "stop" 특수 문자를 보내십시오.
- 전경과 배경에 관계없이 데몬으로 무언가를 실행하려면 시스템의 서비스 관리 하위 시스템이 무엇이든 서비스 정의를 만듭니다.
추가 읽기
- "백스테이지 과정". 기본 정의. 단일 UNIX 사양. IEEE 1003.1. 2018. 그룹을 엽니다.
tcsetpgrp
. 시스템 인터페이스. 단일 UNIX 사양. IEEE 1003.1. 2018. 그룹을 엽니다.- "범용 터미널 인터페이스". 기본 정의. 단일 UNIX 사양. IEEE 1003.1. 2008. 그룹을 엽니다.
- 조나단 드보인 폴라드(2001). "단지 "데몬을 배경에 놓기" 위해서만 fork()를 사용하지 마세요.". Unix 데몬을 설계할 때 피해야 할 실수. 일반적인 답변.
- 조나단 데보인 폴라드(2015).
service
더 이상 명령에 문제가 없습니다..노쉬 페이지. JdeBP 소프트웨어. - 조나단 데보인 폴라드(2018). Unix 서비스 액세스 도구. 일반적인 답변.
- https://unix.stackexchange.com/a/401611/5132
- 프런트엔드 터미널 액세스를 통해 백그라운드에서 명령 실행
- 포그라운드 프로세스 그룹에 하위 프로세스를 추가할 수 없습니다.
답변3
예. 배경이 작동하는 기본 방식은 fork()
그 자체로 자식에서 계속 작업하면서 부모를 완성하는 것입니다. 여기에는 일반적으로 작업 디렉터리를 다음으로 변경 /
(분리된 프로세스로 인해 파일 시스템이 마운트 해제되는 것을 방지하지 않도록), 파일 설명자를 닫고(TTY 신호를 방지하기 위해) 새 프로세스 세션을 만드는 것도 포함됩니다(참조:ID 설정(2))
유사한 라이브러리 기능이 있습니다악마이는 다음과 같은 모든 작업을 단순화합니다.
#define _DEFAULT_SOURCE // glibc >= 2.19
#define _BSD_SOURCE // glibc <= 2.19
#include <unistd.h>
int main() {
daemon(0, 0);
....
}