쉘 스크립트의 집계 파일 설명자

쉘 스크립트의 집계 파일 설명자

나는 이것이 중단 없이 페어링을 제공할 것이라고 생각했지만 begin-end그렇지 않습니다.

#!/bin/bash
fun()(
    flock 1 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
    echo "$BASHPID begin"
    sleep 1;
    echo "$BASHPID end"
)
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
wait

내가 뭘 잘못했나요?

답변1

이 접근 방식은 다음과 같이 작동합니다.

fun()(
  (flock 9 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
   echo "$BASHPID begin"
   sleep 1;
   echo "$BASHPID end"
  ) 9>test
)

이렇게 하면 보호해야 하는 명령이 완료되지 않는 한 잠긴 파일이 닫히지 않습니다. (물론 test더 적합한 것으로 교체해야 합니다 .예를 들어사용 mktemp. )

답변2

실패의 이유는 다음과 같습니다.man 2 flock:

Flock()에 의해 생성된 잠금은 열린 파일 설명과 연결됩니다(open(2) 참조). 이는 중복된 파일 설명자(예를 들어, fork(2) 또는 dup(2)에 의해 생성됨)가 동일한 잠금을 참조하고 이러한 설명자 중 하나를 사용하여 잠금을 수정하거나 해제할 수 있음을 의미합니다.

이는 모든 프로세스가 동일한 파일 설명자를 상속하므로 프로세스 중 하나가 잠금을 수행하면 모두 파일 설명자를 공유한다는 의미입니다. 동일한 파일 설명자를 두 번 잠그는 것은 아무 일도 하지 않습니다.

나의 일반적인 해결책은 스크립트 자체를 잠그는 것입니다(그러나 동시에 스크립트를 여러 번 실행하면 문제가 발생합니다).

#!/bin/bash
fun()(
    exec 3<"$0"
    flock 3 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
    echo "$BASHPID begin"
    sleep 1;
    echo "$BASHPID end"
)
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
wait

답변3

제가 생각하는 핵심은 다음과 같습니다.

  • file descriptor1 예약되어 stdout사용됩니다. stdin/out/err이 아닌 9와 같은 다른 것을 사용해야 합니다.명 1 그룹예시가 표시됩니다.

  • flock with file descriptor잠긴 파일은 아래와 같이 지정된 파일 설명자 번호를 사용하여 열어야 합니다.명 1 그룹예는 다음과 같습니다:

    (
      flock -n 9 || exit 1
      # ... commands executed under lock ...
    ) 9>/var/lock/mylockfile
    

답은 @Stephen Kitt의 것이었습니다.

관련 정보