프로세스를 종료하고 PID가 재사용되지 않았는지 확인하는 방법


40

예를 들어, 다음과 유사한 쉘 스크립트가 있다고 가정하십시오.

longrunningthing &
p=$!
echo Killing longrunningthing on PID $p in 24 hours
sleep 86400
echo Time up!
kill $p

트릭을해야합니까? 프로세스가 조기에 종료되고 PID가 재활용되었을 수 있다는 점을 제외하고 일부 무고한 작업이 대신 신호 대기열에 폭탄을 가져옵니다. 실제로 이것은 문제가 될 수 있지만 그럼에도 불구하고 저를 걱정합니다. FS에서 PID를 유지하거나 제거하기 위해 장기적으로 해킹을 해킹하는 것이 좋지만 여기서 일반적인 상황을 생각하고 있습니다.


3
대상 프로세스가 죽으면 프로세스에서 해당 킬러가 종료됩니다.
mikeserv

2
killallname과 일치하는 항목을 사용 하므로 적어도 같은 이름의 프로세스 만 종료 longrunningthing합니다. 한 번에이 중 하나만 실행한다고 가정합니다.
LawrenceC

8
원래 프로세스의 시작 시간을 저장하고 종료하기 전에 해당 pid가있는 프로세스의 시작 시간이 저장 한 것과 일치하는지 확인하십시오. 쌍의 PID, 시작 시간 리눅스의 프로세스에 대한 고유 식별자.
Bakuriu

1
필요한지 물어봐도 될까요? 달성하려는 기본 사항은 무엇입니까? (연속적으로 실행되지만 24 시간마다 재설정되는 것?)
Olivier Dulac

2
@mikeserv 프로세스는 자체 사망시 무언가가 발생할 것이라고 보장 할 수 없습니다.
kasperd

답변:


29

가장 timeout적합한 명령 을 사용하는 것이 가장 좋습니다.

timeout 86400 cmd

현재 (8.23) GNU 구현은 최소한 alarm()자식 프로세스를 기다리는 동안 사용 하거나 이와 동등한 방식으로 작동 합니다. 돌아오고 나가는 SIGALRM사이에 전달되는 것을 막지 않는 것 같습니다 (효과적으로 경보를 취소합니다 ). 작은 창 에서 stderr에 메시지를 작성할 수도 있습니다 (예를 들어, 자식이 코어를 덤프 한 경우). 경주 창을 더 확장 할 수 있습니다 (예를 들어 stderr가 전체 파이프 인 경우 무기한).waitpid()timeouttimeout

나는 개인적으로 그 한계를 가지고 살 수 있습니다 (이것은 아마도 미래 버전에서 수정 될 것입니다). timeout또한 올바른 종료 상태를보고하고 다른 코너 사례 (시작시 SIGALRM 차단 / 시작시 무시, 기타 신호 처리 등)를 처리하는 데주의를 기울여야합니다.

근사치로 다음 perl과 같이 작성할 수 있습니다 .

perl -MPOSIX -e '
  $p = fork();
  die "fork: $!\n" unless defined($p);
  if ($p) {
    $SIG{ALRM} = sub {
      kill "TERM", $p;
      exit 124;
    };
    alarm(86400);
    wait;
    exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
  } else {exec @ARGV}' cmd

http://devel.ringlet.net/sysutils/timelimit/에timelimit 명령 이 있습니다 (GNU 를 몇 개월 앞두고 ).timeout

 timelimit -t 86400 cmd

alarm()메커니즘 은 유사한 메커니즘을 사용하지만 처리되지 않은 SIGCHLD자식을 무시 하는 처리기를 설치 하여 자식 죽어가는 것을 감지합니다. 또한 실행하기 전에 알람 취소 waitpid()(의 전달을 취소하지 않습니다 SIGALRM이 계류중인 경우, 그러나이 표기되는 방법은, 나는 그것이 문제가되는 볼 수 없습니다) 및 죽이기 전에 호출 waitpid()그래서 다시 PID를 죽일 수 없어 ( ).

netpipes 에도 timelimit명령이 있습니다. 그 중 하나는 수십 년 전에 다른 모든 것보다 오래 걸리고 또 다른 접근법을 취하지 만 중지 된 명령에 대해서는 제대로 작동하지 않으며 1시간 초과시 종료 상태를 반환합니다 .

질문에 대한보다 직접적인 답변으로 다음과 같은 작업을 수행 할 수 있습니다.

if [ "$(ps -o ppid= -p "$p")" -eq "$$" ]; then
  kill "$p"
fi

즉, 프로세스가 여전히 우리의 자식인지 확인하십시오. 다시 말하지만, 프로세스가 종료되고 다른 프로세스에서 해당 pid를 재사용 할 수 있는 작은 경쟁 기간이 있습니다 ( ps해당 프로세스의 상태 검색 및 종료 사이 kill).

일부 껍질 ( zsh, bash, mksh), 당신은 작업 사양 대신 PID를 전달할 수 있습니다.

cmd &
sleep 86400
kill %
wait "$!" # to retrieve the exit status

하나의 백그라운드 작업 만 생성하는 경우에만 작동합니다 (그렇지 않으면 올바른 jobspec을 얻는 것이 항상 안정적으로 가능한 것은 아닙니다).

이것이 문제라면 새로운 쉘 인스턴스를 시작하십시오.

bash -c '"$@" & sleep 86400; kill %; wait "$!"' sh cmd

자식 죽으면 쉘이 작업 테이블에서 작업을 제거하기 때문에 작동합니다. 쉘이 호출 kill()할 때까지 SIGCHLD 신호가 처리되지 않았고 pid를 재사용 할 수 없거나 (기다리지 않았기 때문에) pid를 처리 할 수 ​​없거나 처리되고 작업이 프로세스 테이블에서 제거되었으며 kill오류를보고합니다. bashkill작업 테이블에 액세스하기 전에 SIGCHLD를 %차단하고 확장 한 후에는 차단을 해제합니다 kill().

그 것을 피하기 위해 또 다른 옵션 sleep후에도 주위를 어슬렁 과정 cmd과, 죽은 bashksh93에 파이프를 사용하는 read -t대신 sleep:

{
  {
    cmd 4>&1 >&3 3>&- &
    printf '%d\n.' "$!"
  } | {
    read p
    read -t 86400 || kill "$p"
  }
} 3>&1

여전히 경쟁 조건이 있으며 명령의 종료 상태를 잃게됩니다. 또한 cmdfd 4를 닫지 않는다고 가정합니다 .

다음 perl과 같이 레이스없는 솔루션을 구현해 볼 수 있습니다 .

perl -MPOSIX -e '
   $p = fork();
   die "fork: $!\n" unless defined($p);
   if ($p) {
     $SIG{CHLD} = sub {
       $ss = POSIX::SigSet->new(SIGALRM); $oss = POSIX::SigSet->new;
       sigprocmask(SIG_BLOCK, $ss, $oss);
       waitpid($p,WNOHANG);
       exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
           unless $? == -1;
       sigprocmask(SIG_UNBLOCK, $oss);
     };
     $SIG{ALRM} = sub {
       kill "TERM", $p;
       exit 124;
     };
     alarm(86400);
     pause while 1;
   } else {exec @ARGV}' cmd args...

(다른 유형의 코너 케이스를 처리하려면 개선해야합니다).

경쟁이없는 또 다른 방법은 프로세스 그룹을 사용하는 것입니다.

set -m
((sleep 86400; kill 0) & exec cmd)

그러나 프로세스 그룹을 사용하면 관련된 터미널 장치에 대한 I / O가있는 경우 부작용이 발생할 수 있습니다. 에 의해 생성 된 다른 모든 추가 프로세스를 종료하는 추가 이점이 cmd있습니다.


4
가장 좋은 방법을 먼저 언급하지 않으시겠습니까?
deltab

2
@deltab : timeout휴대용이 아닙니다. 대답은 휴대용 솔루션을 먼저 언급했습니다.
cuonglm

1
@deltab : 일이 어떻게 작동하는지, 특히 "상식"접근이 어떻게 실패 할 수 있는지에 대한 통찰력을 제공합니다 (스테판은 먼저 물고기에게 물고기를 가르치는 것을 선호합니다). 하나는 모든 대답을 읽을 것으로 예상된다
올리비에 Dulac을

@Stephane : "올바른 jobspec을 얻는 것이 항상 신뢰할 수있는 것은 아닙니다": 먼저 출력을 계산 jobs한 다음 알 수 없습니다 (다음은 다음에 발생할 일을 제어 할 수있는 자체 쉘이므로). 직업은 N + 1입니까? [그러면 N을 구하고 나중에 % N + 1을 죽일 수 있습니다]
Olivier Dulac

1
@OlivierDulac, 새 작업을 시작할 때까지 과거 작업이 종료되지 않았다고 가정합니다 (쉘은 작업 번호를 재사용합니다).
Stéphane Chazelas

28

일반적으로 할 수 없습니다. 지금까지 제공된 모든 답변은 버그가있는 휴리스틱입니다. pid를 사용하여 신호를 안전하게 보낼 수있는 경우는 한 가지뿐입니다. 대상 프로세스가 신호를 전송할 프로세스의 직접적인 자식이고 부모가 아직 신호를 기다리지 않은 경우입니다. 이 경우, 종료 된 경우에도 부모가 기다릴 때까지 pid가 예약됩니다 ( "좀비 프로세스"입니다). 나는 껍질로 깨끗하게 할 수있는 방법을 모른다.

프로세스를 강제 종료하는 또 다른 안전한 방법은 마스터 측이 소유 한 의사 터미널로 설정된 제어 tty로 프로세스를 시작하는 것입니다. 그런 다음 터미널을 통해 신호를 보낼 수 있습니다 (예 : pty 의 문자 쓰기 SIGTERM또는 SIGQUITpty 이상).

스크립팅에서 더 편리한 또 다른 방법은 명명 된 screen세션 을 사용하고 명령을 화면 세션에 보내서 종료하는 것입니다. 이 프로세스는 스크린 세션에 따라 명명 된 파이프 또는 유닉스 소켓에서 발생하며 안전한 고유 이름을 선택하면 자동으로 재사용되지 않습니다.


4
왜 껍질에서 할 수 없었는지 알 수 없습니다. 몇 가지 해결책을 제시했습니다.
Stéphane Chazelas

3
레이스 윈도우 및 기타 단점에 대한 설명과 정량적 토론을 제공해 주시겠습니까? 그것 없이는, "지금까지 주어진 모든 답변은 버그가있는 휴리스틱입니다" 는 이점없이 불필요하게 대립하는 것입니다.
peterph

3
@ peterph : 일반적으로 pid를 사용하는 것은 TOCTOU 경주입니다. 여러분이 참조 할 것으로 예상되는 동일한 프로세스를 계속 참조하는지 여부에 관계없이 해당 프로세스 참조를 중단하고 새로운 프로세스를 참조 할 수 있습니다 신호를 보내기 전에 사용하십시오. 이를 방지하는 유일한 방법은 pid의 해제 / 재사용을 차단할 수 있으며,이를 수행 할 수있는 유일한 프로세스는 직접 상위입니다.
R ..

2
@ StéphaneChazelas : 쉘이 종료 된 백그라운드 프로세스의 pid를 기다리는 것을 어떻게 방지합니까? 그렇게 할 수 있으면 OP가 필요한 경우 문제를 쉽게 해결할 수 있습니다.
R ..

5
@ peterph : "경주 창이 작습니다"는 해결책이 아닙니다. 그리고 인종의 희귀 성은 순차적 pid 할당에 달려 있습니다. 일년에 한 번 매우 나쁜 일이 발생하는 버그는 진단 및 수정이 사실상 불가능하기 때문에 항상 발생하는 버그보다 훨씬 더 나쁩니다.
R ..

10
  1. 프로세스를 시작할 때 시작 시간을 저장하십시오.

    longrunningthing &
    p=$!
    stime=$(TZ=UTC0 ps -p "$p" -o lstart=)
    
    echo "Killing longrunningthing on PID $p in 24 hours"
    sleep 86400
    echo Time up!
    
  2. 프로세스를 종료하기 전에 중지하십시오 (정말 필수는 아니지만 경쟁 조건을 피하는 방법입니다. 프로세스를 중지하면 pid를 재사용 할 수 없음)

    kill -s STOP "$p"
    
  3. 해당 PID가있는 프로세스의 시작 시간이 동일한 지 확인하고 그렇다면, 종료하고 그렇지 않으면 프로세스를 계속하십시오.

    cur=$(TZ=UTC0 ps -p "$p" -o lstart=)
    
    if [ "$cur" = "$stime" ]
    then
        # Okay, we can kill that process
        kill "$p"
    else
        # PID was reused. Better unblock the process!
        echo "long running task already completed!"
        kill -s CONT "$p"
    fi
    

주어진 OS 에서 동일한 PID 시작 시간을 가진 프로세스가 하나만있을 수 있기 때문에 작동합니다 .

점검 중에 프로세스를 중지하면 경쟁 조건이 문제가되지 않습니다. 분명히 이것은 임의의 임의의 프로세스가 몇 밀리 초 동안 중단 될 수 있다는 문제가있다. 프로세스 유형에 따라 문제가 될 수도 있고 아닐 수도 있습니다.


개인적으로 나는 단순히 파이썬을 사용하고 psutilPID 재사용을 자동으로 처리합니다.

import time

import psutil

# note: it would be better if you were able to avoid using
#       shell=True here.
proc = psutil.Process('longrunningtask', shell=True)
time.sleep(86400)

# PID reuse handled by the library, no need to worry.
proc.terminate()   # or: proc.kill()

유닉스의 파이썬 규칙 ... 대부분의 시스템에서 사용을 금지하지 않기 때문에 더 많은 답변이 시작되지 않는 이유는 확실하지 않습니다.
Mr. Mascaro

전에 비슷한 방식을 사용했지만 (시작 시간 사용) sh 스크립팅 기술이 내 것보다 깔끔합니다! 감사.
FJL

이는 잠재적으로 잘못된 프로세스를 중지하고 있음을 의미합니다. 참고 ps -o start=잠시 후 Jan26에 18시 12분에서 형식 변경을. DST 변경도주의하십시오. 리눅스라면 아마을 선호 할 것이다 TZ=UTC0 ps -o lstart=.
Stéphane Chazelas

@ StéphaneChazelas 네,하지만 나중에 계속 진행할 수 있습니다. 나는 분명히 말했다 : 그 프로세스가 수행하는 작업 유형에 따라 몇 밀리 초를 멈추는 데 약간의 문제가있을 수 있습니다. 에 대한 팁 주셔서 감사합니다 lstart, 나는 그것을 편집합니다.
Bakuriu

시스템이 사용자 당 프로세스 수를 제한하지 않는 한 누구나 프로세스 테이블을 좀비로 쉽게 채울 수 있습니다. 3 개의 사용 가능한 pid가 남아 있으면 누구나 1 초 내에 동일한 pid로 수백 개의 서로 다른 프로세스를 쉽게 시작할 수 있습니다. 따라서 엄밀히 말하면 "주어진 OS에서 동일한 PID 및 시작 시간을 가진 프로세스가 하나만있을 수 있습니다" 는 반드시 사실은 아닙니다.
Stéphane Chazelas

7

Linux 시스템에서는 pid 네임 스페이스를 유지하여 pid가 재사용되지 않도록 할 수 있습니다. /proc/$pid/ns/pid파일을 통해 수행 할 수 있습니다 .

  • man namespaces -

    이 디렉토리에있는 파일 중 하나를 파일 시스템의 다른 곳에 바인드 마운트 (참조 mount(2)) 하면 현재 네임 스페이스에있는 모든 프로세스가 종료 되더라도 pid에 의해 지정된 프로세스의 해당 네임 스페이스가 유지됩니다.

    이 디렉토리의 파일 중 하나 (또는 이러한 파일 중 하나에 바인드 마운트 된 파일)를 열면 pid로 지정된 프로세스의 해당 네임 스페이스에 대한 파일 핸들이 리턴됩니다. 이 파일 설명자가 열려있는 한 네임 스페이스의 모든 프로세스가 종료 되더라도 네임 스페이스는 활성 상태로 유지됩니다. 파일 디스크립터는로 전달 될 수 있습니다 setns(2).

이름을 지정하여 프로세스 그룹 (기본적으로 임의의 수의 프로세스)을 분리 할 수 ​​있습니다 init.

  • man pid_namespaces -

    새로운 공간에 만들어진 제 과정 (즉, 처리를 사용하여 생성 clone(2) 으로 CLONE_NEWPID 플래그 나 호출 후 처리에 의해 생성 된 제 자식 unshare(2)은 USING CLONE_NEWPID 플래그) 있다 PID 1 및 인 init네임 스페이스에 대한 프로세스 ( 참조 init(1)) . 네임 스페이스 내에서 분리 된 하위 프로세스 init(1) 는 동일한 PID 네임 스페이스 에서 하위의 조상 중 하나가 prctl(2) PR_SET_CHILD_SUBREAPER 명령을 사용하여 독립된 하위 프로세스 의 리퍼 로 표시 하지 않는 한이 프로세스 상위 프로세스가됩니다 .

    PID 네임 스페이스 의 init프로세스가 종료되면 커널은 SIGKILL 신호 를 통해 네임 스페이스의 모든 프로세스를 종료합니다 . 이 동작은 프로세스가 PID 네임 스페이스 의 올바른 작동에 필수적 이라는 사실을 반영합니다 .init

util-linux패키지는 네임 스페이스를 조작하는 데 유용한 많은 도구를 제공합니다. 예를 들어, unshare사용자 네임 스페이스에 대한 권한을 아직 준비하지 않은 경우 수퍼 유저 권한이 필요합니다.

unshare -fp sh -c 'n=
    echo "PID = $$"
    until   [ "$((n+=1))" -gt 5 ]
    do      while   sleep 1
            do      date
            done    >>log 2>/dev/null   &
    done;   sleep 5' >log
cat log; sleep 2
echo 2 secs later...
tail -n1 log

사용자 네임 스페이스를 정렬하지 않은 경우 권한을 즉시 삭제하여 임의의 명령을 안전하게 실행할 수 있습니다. 이 runuser명령은 패키지에서 제공하는 또 다른 (비 setuid) 바이너리 util-linux이며 통합하면 다음과 같습니다.

sudo unshare -fp runuser -u "$USER" -- sh -c '...'

...등등.

상기 예에서, 2 개 개의 스위치에 전달 불려하게 플래그 제 자식 프로세스를 생성하고 그 보장 상태 및 지시 플래그 PID를 스페이스를 만들.unshare(1)--forksh -cinit--pidunshare(1)

sh -c프로세스는 5 개의 백그라운드 하위 쉘을 생성합니다. 각 쉘은 무한 while루프 로 true 를 반환 하는 한 계속해서 date끝에 출력을 추가 합니다. 이 프로세스를 생성 한 후 추가 5 초 동안 호출 한 다음 종료됩니다.logsleep 1shsleep

-f플래그가 사용되지 않으면 백그라운드 while루프 중 어느 것도 종료되지 않지만 그와 함께 종료 된다는 점에 주목할 가치가 있습니다.

산출:

PID = 1
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:45 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:46 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:47 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
Mon Jan 26 19:17:48 PST 2015
2 secs later...
Mon Jan 26 19:17:48 PST 2015

강력 해 보이는 흥미로운 답변. 아마도 기본적인 사용법에는 약간의 과잉이지만 아마도 생각할 가치가 있습니다.
우리엘

PID 네임 스페이스를 유지하는 것이 PID 재사용을 방지하는 방법 또는 이유를 알 수 없습니다. 인용 한 맨 페이지 ( 이 파일 설명자가 열려있는 한 네임 스페이스의 모든 프로세스가 종료 되더라도 네임 스페이스는 활성 상태로 유지됨) 는 프로세스가 여전히 종료 될 수 있음을 나타냅니다 (따라서 프로세스 ID가 재활용 될 수 있음). PID 네임 스페이스를 유지하는 것은 PID 자체가 다른 프로세스에 의해 재사용되지 않도록하는 것과 어떤 관련이 있습니까?
davmac

5

longrunningthing좀 더 데몬과 비슷한 방식으로 동작을 개선 하십시오 . 예를 들어 프로세스를 최소한 제한적으로 제어 할 수 있는 pidfile 을 만들 수 있습니다 . 래퍼를 포함하는 원래 바이너리를 수정하지 않고 여러 가지 방법으로이 작업을 수행 할 수 있습니다. 예를 들면 다음과 같습니다.

  1. 백그라운드에서 필요한 작업을 시작하고 (선택적 출력 리디렉션 사용) 간단한 프로세스 래퍼 스크립트를 사용하여이 프로세스의 PID를 파일에 쓴 다음 프로세스가 완료 될 때까지 기다렸다가 (사용 wait) 파일을 제거하십시오. 대기 중 프로세스가 예를 들어

    kill $(cat pidfile)
    

    래퍼는 pidfile이 제거되었는지 확인합니다.

  2. 모니터 래퍼 는 자체 PID를 어딘가에 배치 하고 여기에 전송 된 신호를 포착 (및 응답)합니다. 간단한 예 :

    #!/bin/bash
    p=0
    trap killit USR1

    killit () {
        printf "USR1 caught, killing %s\n" "$p"
        kill -9 $p
    }

    printf "monitor $$ is waiting\n"
    therealstuff &
    p=%1
    wait $p
    printf "monitor exiting\n"

이제 @R ..과 @ StéphaneChazelas가 지적했듯이 이러한 접근 방식은 종종 경쟁 조건을 갖거나 생성 가능한 프로세스 수에 제한을가합니다. 또한 longrunningthingmay 포크와 어린이가 분리 되는 경우를 처리하지 않습니다 (원래 질문의 문제가 아닐 수도 있음).

최근의 리눅스 커널 (세 몇 읽기)이 멋지게 사용하여 처리 할 수 cgroup을 , 즉 냉장고 - 나는 가정, 일부 현대적인 리눅스 시스템을 사용하는 init을 것입니다.


감사합니다. 나는 모든 것을 읽고 longrunningthing있습니다. 또한 문제를 설명했기 때문에 쉘 스크립트 예제를 제공했습니다. 나는 당신과 다른 모든 창조적 인 솔루션을 좋아하지만 Linux / bash를 사용하는 경우 "시간 초과"가 내장되어 있습니다. 나는 그 소스를 가져 와서 어떻게 작동하는지보아야한다고 가정합니다!
FJL

@FJL timeout은 쉘 내장 이 아닙니다 . timeoutLinux에 대한 다양한 명령 구현이 있으며 , 하나는 최근에 (2008 년) GNU coreutils에 추가되었으므로 (Linux에 국한되지 않음) 오늘날 대부분의 Linux 배포에서 사용됩니다.
Stéphane Chazelas

@ Stéphane-고마워-나는 GNU coreutils에 대한 언급을 찾았다. 이식 가능하지만 기본 시스템에 의존하지 않으면 신뢰할 수 없습니다. 나는 그것이 어떻게 작동하는지 아는 데 더 관심이 있지만, 다른 곳에서는 귀하의 의견이 100 % 신뢰할 수 없다고 제안합니다. 이 스레드가 사라진 방식을 생각하면 놀라지 않습니다!
FJL

1

리눅스 (그리고 몇 가지 다른 *의 nixes도)에서 실행중인 경우, 당신은 죽일하려는 프로세스가 계속 사용하는 경우 당신은 확인할 수 명령 줄은 긴 과정과 일치하는지 확인합니다. 같은 것 :

echo Time up!
grep -q longrunningthing /proc/$p/cmdline 2>/dev/null
if [ $? -eq 0 ]
then
  kill $p
fi

다른 방법은 다음과 같이 종료하려는 프로세스가 얼마나 오래 실행되는지 확인하는 것 ps -p $p -o etime=입니다. 에서이 정보를 추출하여 직접 할 수는 /proc/$p/stat있지만 까다로울 수 있습니다 (시간은 지 피지로 측정되며 시스템 가동 시간 /proc/stat도 사용해야합니다 ).

어쨌든 일반적으로 검사 프로세스를 종료 하기 전에 프로세스가 교체되지 않도록 보장 할 수 없습니다 .


경쟁 조건을 제거하지 않기 때문에 여전히 올바르지 않습니다.
strcat

@strcat 실제로, 성공의 보증은 없지만 대부분의 스크립트는 그러한 검사를 귀찮게하지 않으며 cat pidfile결과를 무의미하게 죽일뿐입니다 . 나는 껍질에서만 그것을하는 깨끗한 방법을 기억할 수 없다. 제안 된 네임 스페이스 답변은 흥미로운 질문처럼 보입니다.
Uriel

-1

이것은 실제로 매우 좋은 질문입니다.

프로세스 고유성을 결정하는 방법은 (a) 메모리의 어디에 있는지; 그리고 (b) 그 기억에 포함 된 것. 구체적으로 말하면, 각 스레드의 텍스트 영역이 메모리에서 다른 위치를 차지할 것이므로 메모리에서 초기 호출을위한 프로그램 텍스트가 어디에 있는지 알고 싶습니다. 프로세스가 종료되고 동일한 pid로 다른 프로세스가 시작되면 새 프로세스의 프로그램 텍스트는 메모리에서 동일한 위치를 차지하지 않으며 동일한 정보를 포함하지 않습니다.

따라서 프로세스를 시작한 직후 md5sum /proc/[pid]/maps결과를 저장하십시오. 나중에 프로세스를 종료하려면 다른 md5sum을 수행하고 비교하십시오. 일치하면 pid를 죽입니다. 그렇지 않다면하지 마십시오.

이것을 직접 보려면 두 개의 동일한 bash 쉘을 시작하십시오. /proc/[pid]/maps그들 에 대해 조사하면 그들이 다르다는 것을 알게 될 것입니다. 왜? 비록 동일한 프로그램이지만 메모리에서 다른 위치를 차지하고 스택의 주소가 다릅니다. 따라서 프로세스가 종료되고 PID가 재사용 되는 경우 동일한 인수를 사용하여 동일한 명령을 다시 시작하더라도 "maps"파일은 달라지며 원래 프로세스를 처리하고 있지 않다는 것을 알게됩니다.

자세한 내용은 proc 매뉴얼 페이지 를 참조하십시오.

파일이 있음을 참고 /proc/[pid]/stat하면 기본으로이 파일을 사용하는 것을 선호 그렇다면, 등의 과정, 부모 PID의 연령이 파일은 정적 정보와 동적 정보를 모두 포함 : 이미 다른 포스터의이 대답에 언급 된 것을 모든 정보가 들어 를 비교 한 다음을 시작 longrunningthing하면 stat파일 에서 다음 정적 필드를 추출하여 나중에 비교할 수 있도록 저장해야합니다.

pid, 파일 이름, 부모의 pid, 프로세스 그룹 ID, 제어 터미널, 시스템 부팅 후 시작된 시간 프로세스, 상주 세트 크기, 스택 시작 주소,

위와 같이 종합하면 위의 과정이 고유하게 식별되므로 다른 방법으로 진행할 수 있습니다. 실제로 "pid"및 "시스템 부팅 후 시간 프로세스 시작"이상을 확신 할 수 있습니다. stat파일 에서 이러한 필드를 추출 하여 프로세스를 시작할 때 어딘가에 저장하십시오. 나중에 죽이기 전에 다시 추출하고 비교하십시오. 일치하면 원래 프로세스를보고있는 것입니다.


1
즉, 일반적으로하지 않습니다 작품으로 /proc/[pid]/maps추가 메모리와 같은 시간에 변화가 할당 또는 무엇을하지 스택이 증가하거나 새로운 파일이 mmap 된 있습니다 ... 그리고 즉시 시작 후 평균? 모든 라이브러리가 축소 된 후? 그걸 어떻게 알아?
Stéphane Chazelas

현재 두 가지 프로세스, 하나는 Java 응용 프로그램과 다른 하나는 cfengine 서버로 시스템에서 테스트하고 있습니다. 15 분마다 md5sum지도 파일을 작성합니다. 나는 하루나 이틀 동안 실행하고 결과와 함께 여기에 다시보고합니다.
Michael Martinez

@ StéphaneChazelas : 저는 지금 두 시간 동안 16 시간 동안 두 가지 프로세스를 확인했지만 md5sum에는 아무런 변화가 없었습니다
Michael Martinez

-1

다른 방법은 프로세스를 종료하기 전에 프로세스의 수명을 확인하는 것입니다. 이렇게하면 24 시간 이내에 생성되지 않은 프로세스를 종료하지 않을 수 있습니다. if프로세스를 종료하기 전에 조건에 따라 조건을 추가 할 수 있습니다 .

if [[ $(ps -p $p -o etime=) =~ 1-. ]] ; then
    kill $p
fi

if조건은 프로세스 ID $p가 24 시간 (86400 초) 미만 인지 확인합니다 .

PS :-명령 ps -p $p -o etime=은 형식을 갖습니다<no.of days>-HH:MM:SS


mtime의는 /proc/$p프로세스의 시작 시간과는 아무 상관이 없습니다.
Stéphane Chazelas

감사합니다 @ StéphaneChazelas. 네 말이 맞아 if조건 을 변경하기 위해 답변을 편집했습니다 . 버그가 있으면 의견을 주시기 바랍니다.
Sree

-3

내가하는 일은 프로세스를 종료 한 후 다시 수행하는 것입니다. 내가 대답 할 때마다 "아무런 과정도 없다"

allenb   12084  5473  0 08:12 pts/4    00:00:00 man man
allenb@allenb-P7812 ~ $ kill -9 12084
allenb@allenb-P7812 ~ $ kill -9 12084
bash: kill: (12084) - No such process
allenb@allenb-P7812 ~ $ 

더 간단 할 수 없었고 나는 몇 년 동안 아무런 문제없이 이것을 해왔습니다.


그것은 "어떻게 고칠 수 있을까"가 아니라 "어떻게하면 나빠질 수 있을까"라는 질문에 대한 답입니다.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.