读取超时参数(-t)不起作用?

Max*_*tti 6 bash timeout read

我不知道一般如何解释这个问题,所以我就用这个例子:

#!/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
Run Code Online (Sandbox Code Playgroud)

现在我希望每个读取线程都占用一行(或几行),但第一次读取过程将占用所有行(以我不理解的随机顺序,但没关系),将其放在某个缓冲区中并且所有其他读取过程都不会得到任何一行。

此外,提供给读取命令的超时参数似乎不起作用,因为阅读器 2-10 没有退出。

  1. 为什么?
  2. 我该如何解决这个问题,使线条(在某种程度上)均匀分布在读者中?

xhi*_*nne 9

read超时

read超时实际上有效。这里的问题是在读取模式下打开 FIFO 会阻塞,直到 FIFO 在写入模式下打开。在这种情况下,这不是read被阻止,而是bash在将 FIFO 重定向到标准输入时。

一旦其他进程打开 FIFO 进行写入,bash将成功打开 FIFO 进行读取并执行read命令(这将按预期超时)。

如果您使用的是 Linux,fifo手册页告诉我们“打开 FIFO 进行读写将在阻塞和非阻塞模式下都成功”。因此,即使没有其他进程打开 FIFO 进行写入,以下命令也会超时:

read -st 1 data <> "$fifo"
Run Code Online (Sandbox Code Playgroud)

注意比赛条件

一旦您的 shell 进程打开 FIFO 进行读取,写入器将被解锁,并且当bash将 FIFO 重定向到 stdin 并调用时read,写入器可能能够打开 FIFO 并多次写入其中。由于您一次仅读取一行,因此在两端 FIFO 关闭时剩余的任何要读取的行都将丢失。更好的解决方案是通过将 FIFO 重定向到整个while...done循环的stdin 来保持 FIFO 打开,就像您对 fd 3 所做的那样。类似于:

while ...; do
    ...
    read -st 1 data
    ...
done 3<"$lock" < "$fifo"
Run Code Online (Sandbox Code Playgroud)

或者甚至在更高级别,如果您有多个读者并行。重要的是保持 FIFO 打开。作家方面也是如此。

例如,使用您随更新发布的代码,上层将是:

# Writer
writer > "$myfifo" &

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

当然,删除$myfifo代码中其他任何地方的重定向,并删除编写器echo "$(date -R) writing \"$i\"."中的 ,或将其重定向到 stderr,否则它会进入 FIFO。

  • 从理论上讲,仍然有可能您的 `for` 循环运行得如此之快,以至于它执行了两个循环,而另一端只有一个读取。 (2认同)