이 문제를 어떻게 설명해야 할지 모르겠으므로 다음 예를 사용하겠습니다.
#!/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
read
시간 초과 허용
read
시간 초과가 작동합니다. 여기서 문제는 FIFO가 쓰기 모드로 열릴 때까지 읽기 모드에서 FIFO를 여는 것이 차단된다는 것입니다. 이 경우 read
차단하는 것이 아니라 bash
FIFO가 stdin으로 리디렉션되는 동안 차단하는 것입니다.
다른 프로세스가 쓰기를 위해 FIFO를 열면 bash
읽기를 위해 FIFO를 성공적으로 열고 read
명령을 실행합니다(예상대로 시간 초과됨).
리눅스를 사용하고 계시다면,fifo 매뉴얼 페이지"읽기 및 쓰기를 위해 FIFO를 여는 것은 차단 모드와 비차단 모드 모두에서 성공합니다"라고 알려줍니다. 따라서 다른 프로세스에 쓰기 위해 열려 있는 FIFO가 없더라도 다음 명령은 시간 초과됩니다.
read -st 1 data <> "$fifo"
경쟁 조건에 유의하세요.
쉘 프로세스가 읽기 위해 FIFO를 열면 작성자의 잠금이 해제되고 bash
FIFO가 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로 이동하게 됩니다.