2 Stimmen

Daten im Linux-FIFO scheinen verloren zu gehen

Ich habe ein Bash-Skript, das einige Arbeiten parallel ausführen möchte, indem ich jeden Auftrag in eine Subshell packe, die im Hintergrund ausgeführt wird. Die Anzahl der gleichzeitig laufenden Aufträge sollte begrenzt sein. Dies erreiche ich, indem ich zunächst einige Zeilen in einem FIFO ablege und dann, kurz vor dem Forking der Subshell, das übergeordnete Skript aufgefordert wird, eine Zeile aus diesem FIFO zu lesen. Erst nachdem es eine Zeile erhalten hat, kann es die Subshell forken. Bis jetzt hat alles gut funktioniert. Aber als ich versucht habe, eine Zeile aus dem FIFO in der Subshell zu lesen, scheint es, dass nur eine Subshell eine Zeile bekommen kann, auch wenn es offensichtlich mehr Zeilen im FIFO gibt. Ich frage mich also, warum andere Subshell(s) keine Zeile lesen können, auch wenn mehr Zeilen im FIFO sind.
Mein Testcode sieht in etwa so aus:

#!/bin/sh

fifo_path="/tmp/fy_u_test2.fifo"
mkfifo $fifo_path
#open fifo for r/w at fd 6
exec 6<> $fifo_path

process_num=5
#put $process_num lines in the FIFO

for ((i=0; i<${process_num}; i++)); do
    echo "$i"
done >&6

delay_some(){
    local index="$1"
    echo "This is what u can see. $index \n"
    sleep 20;
}

#In each iteration, try to read 2 lines from FIFO, one from this shell,
#the other from the subshell
for i in 1 2
do
    date >>/tmp/fy_date
#If a line can be read from FIFO, run a subshell in bk, otherwise, block.
    read -u6
    echo " $$ Read --- $REPLY  --- from 6 \n" >> /tmp/fy_date
    {
        delay_some $i
#Try to read a line from FIFO, __ only one subshell succeeds the following line. __
        read -u6
        echo " $$ This is in child # $i, read --- $REPLY --- from 6 \n" >> /tmp/fy_date
    } &
done

Und die Ausgabedatei /tmp/fy_date hat den folgenden Inhalt:

Mon Apr 26 16:02:18 CST 2010
 32561 Read --- 0  --- from 6 \n
Mon Apr 26 16:02:18 CST 2010
 32561 Read --- 1  --- from 6 \n
 32561 This is in child # 1, read --- 2 --- from 6 \n

Dort erwarte ich eine Zeile wie diese:

 32561 This is in child # 2, read --- 3 --- from 6 \n

Aber es erscheint nie, und der Prozess des Kindes Nr. 2 ist dort blockiert, bis ich eine Ausgabe mache:
echo etwas > /tmp/fy_u_test2.fifo

1voto

frankc Punkte 10886

Ist es möglich, dass Ihr Schreiben in den Fifo gepuffert wird? Wenn Sie Unbuffer zur Verfügung haben, könnten Sie versuchen, die Echos mit diesem voranzustellen? Ich sehe nicht wirklich, wie es hier passieren könnte, aber die Symptome passen, also ist es einen Versuch wert.

1voto

Michael Trausch Punkte 3147

Beachten Sie, dass ein FIFO auf POSIX-Systemen im Wesentlichen eine benannte Pipe ist. Um Daten in einer Pipe zu bewegen, braucht eine Seite einen Leser und die andere Seite einen Schreiber, und wenn eine geschlossen wird, verliert die andere ihren Nutzen.

Mit anderen Worten: Sie können nicht cat auf einen Fifo zuzugreifen, nachdem ein anderer Leser das System verlassen hat, da der Inhalt des Fifo verschwunden ist.

Sie können eine normale Datei verwenden (und mit Hilfe von Dateisperren sicherstellen, dass Sie den Zugriff auf diese normale Datei synchronisieren), oder ein Verzeichnis mit mehreren Dateien darin, oder sogar gemeinsam genutzten Speicher oder etwas Ähnliches verwenden (vielleicht aber nicht in einem Shell-Skript). Es hängt alles davon ab, was Ihr Ziel ist, und wie Sie am besten vorgehen.

1voto

Utoah Punkte 1022

Scheint etwas mit dem Shell-Aufruf "read -u6" zu tun zu haben. Wenn ich STDIN der Shell geschlossen habe, versucht sie bei der Ausgabe von 'read -u6', 128 Bytes von fd 6 zu lesen. Bleibt STDIN jedoch unangetastet, werden bei der Ausgabe von 'read -u6' die Bytes nacheinander gelesen, bis ein ' \n ' angetroffen wird. Ich entdeckte diese merkwürdige Aktion durch 'strace', wo im ersten Fall ein 'read -u6'-Aufruf den folgenden Syscall verursachte:

read(6, "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n"..., 128) = 50

und im letzteren Fall löste ein "read -u6"-Aufruf den folgenden Syscall aus:

30371 16:27:15 read(6, "0", 1)          = 1
30371 16:27:15 read(6, "\n", 1)         = 1

Es folgt der Testcode:

#!/bin/bash

fifo_path="/tmp/fy_u_test2.fifo"
mkfifo $fifo_path
#open fifo for r/w at fd 6
exec 6<> $fifo_path

#comment or decomment the following line makes difference
exec 0>&-

process_num=20
#put $process_num lines in the FIFO
for ((i=0;i<${process_num};i++));do
    echo "$i"
done >&6

delay_some(){
    local index="$1"
    echo "This is what u can see. $index \n"
    sleep 10;
}

#In each iteration, try to read 2 lines from FIFO, one from this shell,
#the other from the subshell
for i in 1 2 3
do
    date >>/tmp/fy_date
#If a line can be read from FIFO, run a subshell in bk, otherwise, block.
    read -u6
    echo " $$ Read --- $REPLY  --- from 6 \n" >> /tmp/fy_date
    {
        delay_some $i
#Try to read a line from FIFO
#   read -u6
        echo " $$ This is in child # $i, read --- $REPLY --- from 6 \n" >> /tmp/fy_date
        echo " $$ Again this is in child # $i, read --- $REPLY --- from 6 \n" >> /tmp/fy_date
        echo "$i xx" >&6
#       echo xx >&6
    } &
done

#sleep 13
#wait
#read -u6
echo "$$ After fork, in parent, read --- $REPLY --- from 6 \n" >> /tmp/fy_date

0voto

Dennis Williamson Punkte 322329

Ich erhalte alle vier Zeilen in der Protokolldatei, wenn ich sie ausführe. Was passiert, wenn Sie Ihr Shebang in #!/bin/bash ?

0voto

Dan Andreatta Punkte 3461

Es könnte sich um ein Gleichzeitigkeitsproblem handeln, da beide Subshells gleichzeitig versuchen, aus demselben Fifo zu lesen. Tritt das Problem immer wieder auf?

Sie könnten versuchen, eine flock -x 6 Anweisung oder ändern Sie die Verzögerung für die beiden Subshells und sehen Sie, was passiert.

BTW, ich kann bestätigen, dass mit bash 3.2 und Kernel 2.6.28 Ihr Code funktioniert gut.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X