我写了一个这样的脚本:
N=5
FIFO=/tmp/$$.fifo
mkfifo $FIFO
loop(){
for i in $(seq 1 $N); do
read tmp < $FIFO
echo "$i out"
done
}
loop &
LOOP_PID=$!
for i in $(seq 1 $N); do
echo $i > $FIFO
echo "$i in"
done
wait $LOOP_PID
Run Code Online (Sandbox Code Playgroud)
当我运行脚本时,它停止wait $LOOP_PID并且无法继续。
所以我用文件描述符修改脚本:
N=5
FIFO=/tmp/$$.fifo
mkfifo $FIFO
exec 3<>$FIFO
loop(){
for i in $(seq 1 $N); do
read -u3 tmp
echo "$i out"
done
}
loop &
LOOP_PID=$!
for i in $(seq 1 $N); do
echo $i >&3
echo "$i in"
done
wait $LOOP_PID
Run Code Online (Sandbox Code Playgroud)
还可以。
当我直接使用 FIFO 时,它无法从 FIFO 中连续读取数据并且会卡死。当我使用文件描述符时,没问题。是什么原因?
替换这个:
loop(){
for i in $(seq 1 $N); do
read tmp < $FIFO
echo "$i out"
done
}
Run Code Online (Sandbox Code Playgroud)
有了这个:
loop(){
for i in $(seq 1 $N); do
read tmp
echo "$i out"
done < $FIFO
}
Run Code Online (Sandbox Code Playgroud)
这使 fifo 保持打开状态,而不是在每个循环中重新打开和重新关闭它。
FIFO 非常棘手:
除非另一个进程准备好从 FIFO 读取,否则写入 FIFO 的尝试将被阻塞。
如果从 FIFO 读取的进程关闭了 FIFO,则所有未读信息都会丢失。
这意味着上面的脚本的行为方式可能取决于时间的意外。执行时read tmp < $FIFO,有多少行写入了 FIFO? read将只读取第一个,当 FIFO 关闭时,其余的将被丢弃。
exec帮助让我们比较一下两个脚本。第一种直接使用 FIFO:
#!/bin/sh
fifo=/tmp/$$.myfifo
mkfifo "$fifo"
echo $'1\n2\n3\n4'>"$fifo"
for i in {1..4}
do
read tmp
echo $tmp
done <"$fifo"
Run Code Online (Sandbox Code Playgroud)
上面的脚本将在echo等待进程开始读取 FIFO 的第一个过程中挂起。因为它挂在那里,所以read tmp永远不会到达该语句,并且该脚本不会产生任何输出。
第二个用于exec创建文件句柄:
#!/bin/sh
fifo=/tmp/$$.myfifo
mkfifo "$fifo"
exec 3<>"$fifo"
echo $'1\n2\n3\n4'>&3
for i in {1..4}
do
read -u3 tmp
echo $tmp
done
Run Code Online (Sandbox Code Playgroud)
该脚本不会挂起,并将产生四行输出。不同之处在于 shell 在文件句柄上提供缓冲。因此,当第一个echo语句尝试写入 FIFO 时,shell 已准备好从 FIFO 读取。shell 读取的数据可用于该read -u3 tmp语句。
| 归档时间: |
|
| 查看次数: |
1237 次 |
| 最近记录: |