읽기 시간 초과 매개변수(-t)가 작동하지 않습니까?

읽기 시간 초과 매개변수(-t)가 작동하지 않습니까?

이 문제를 어떻게 설명해야 할지 모르겠으므로 다음 예를 사용하겠습니다.

#!/bin/bash

cleanup() {
    rm "$myfifo"
    rm "$mylock"
    kill '$(jobs -p)'
}

writer() {
    for i in $(seq 0 100); do
        echo "$(date -R) writing \"$i\"."
        echo "$i" > "$myfifo"
    done
}

reader() {
    while true; do
        flock 3
        read -st 1 line
        status=$?
        if [ $status -eq 0 ]; then
            echo "$(date -R) reading \"$line\" in thread $1."
        else
            echo "$(date -R) status $status in thread $1.
            break
        fi
        flock -u 3
        sleep 10
    done 3<"$mylock" <"$myfifo"
}

trap cleanup EXIT

myfifo="$(mktemp)"
mylock="$(mktemp)"

rm "$myfifo"
mkfifo "$myfifo"

writer &

for i in $(seq 1 10); do
    reader $i &
    sleep 1
done

wait

이제 읽기 스레드가 각각 한 줄(또는 몇 줄)을 읽기를 원하지만 첫 번째 읽기 프로세스는 모든 줄을 읽습니다(무작위 순서로 이해하지 못하지만 중요하지 않음). 버퍼 어딘가에 있고 다른 모든 읽기 프로세스는 행을 얻지 못합니다.

또한 판독기 2-10이 종료되지 않으므로 읽기 명령에 제공된 시간 초과 매개변수가 작동하지 않는 것 같습니다.

  1. 왜?
  2. 행이 독자들 사이에 (어느 정도) 균등하게 분배되도록 이 문제를 어떻게 해결할 수 있습니까?

답변1

read시간 초과 허용

read시간 초과가 작동합니다. 여기서 문제는 FIFO가 쓰기 모드로 열릴 때까지 읽기 모드에서 FIFO를 여는 것이 차단된다는 것입니다. 이 경우 read차단하는 것이 아니라 bashFIFO가 stdin으로 리디렉션되는 동안 차단하는 것입니다.

다른 프로세스가 쓰기를 위해 FIFO를 열면 bash읽기를 위해 FIFO를 성공적으로 열고 read명령을 실행합니다(예상대로 시간 초과됨).

리눅스를 사용하고 계시다면,fifo 매뉴얼 페이지"읽기 및 쓰기를 위해 FIFO를 여는 것은 차단 모드와 비차단 모드 모두에서 성공합니다"라고 알려줍니다. 따라서 다른 프로세스에 쓰기 위해 열려 있는 FIFO가 없더라도 다음 명령은 시간 초과됩니다.

read -st 1 data <> "$fifo"

경쟁 조건에 유의하세요.

쉘 프로세스가 읽기 위해 FIFO를 열면 작성자의 잠금이 해제되고 bashFIFO가 stdin으로 리디렉션되어 호출 되면 read작성자가 FIFO를 열고 여기에 쓸 수 있습니다.여러번. 한 번에 하나의 행만 읽을 수 있으므로 FIFO의 양쪽 끝이 닫히면 읽을 나머지 행이 손실됩니다. 더 나은 해결책은 fd 3에서 했던 것처럼 while루프 전체에서 stdin으로 리디렉션하여 FIFO를 열어 두는 것 입니다 . done다음과 같이:

while ...; do
    ...
    read -st 1 data
    ...
done 3<"$lock" < "$fifo"

또는 병렬 리더가 여러 개 있는 경우에도 마찬가지입니다. FIFO를 열어두는 것이 중요합니다. 작가들도 마찬가지다.

예를 들어 업데이트와 함께 게시한 코드를 사용하면 상위 레이어는 다음과 같습니다.

# Writer
writer > "$myfifo" &

# Reader
for i in $(seq 1 10); do
    reader $i &
    sleep 1
done < "$myfifo"

물론, $myfifo코드의 다른 곳에서 리디렉션을 제거하고 echo "$(date -R) writing \"$i\"."작성기에서 리디렉션을 제거하거나 stderr로 리디렉션하십시오. 그렇지 않으면 FIFO로 이동하게 됩니다.

관련 정보