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

0voto

Utoah Punkte 1022

Ich habe festgestellt, dass Daten, die ungelesen im FIFO verbleiben, wenn die übergeordnete Shell beendet wird, verloren gehen, wenn die übergeordnete Shell beendet wird.
Wenn ich den folgenden Code habe:

#!/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=9
#put $process_num lines in the FIFO

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

for i in 1 2 3;
do
 read -u6
done

Nach Beendigung dieses Codes ergibt der Befehl "cat /tmp/fy_u_test2.fifo" nichts.
ABER wenn ich den folgenden Code habe.

#!/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=9
#put $process_num lines in the FIFO

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

for i in 1 2 3;
do
 read -u6
done
#__ notice this line __
sleep 60

Nach der Ausführung dieses Codes gibt der Befehl "cat /tmp/fy_u_test2.fifo" während der 60 Sekunden, in denen er schläft, folgende Ausgabe:

$ cat /tmp/fy\_u\_test2.fifo 
3
4
5
6
7
8

0voto

lhunath Punkte 111281

Aus Gründen, die bereits in anderen Antworten erläutert wurden, sollten Sie nur dann eine Pipe verwenden, wenn Sie gleichzeitig aus der Pipe lesen und schreiben können.

Es ist daher ratsam, eine andere Art der IPC zu verwenden oder die Verwendung von Fifos so umzustrukturieren, daß ein asynchroner Prozeß die Pipe füllt, während der Hauptprozeß Workprozesse erzeugt (oder umgekehrt).

Hier ist eine Methode, um das Gewünschte mit einer einfachen Datei als eine Art Warteschlange zu erhalten:

#!/usr/bin/env bash

stack=/tmp/stack
> "$stack"

# Create an initial 5 spots on the stack
for i in {1..5}; do
    echo >> "$stack"
done

for i in {1..10}; do
    # Wait for a spot on the stack.
    until read; do sleep 1; done

    {
        echo "Starting process #$i"
        sleep $((5 + $i)) # Do something productive
        echo "Ending process #$i"

        # We're done, free our spot on the stack.
        echo >> "$stack"
    } &
done < "$stack"

Nebenbemerkung: Diese Methode ist nicht ideal für unbegrenzte Arbeit, da sie für jeden aufgerufenen Prozess ein Byte zur Stack-Datei hinzufügt, was bedeutet, dass die Stack-Datei langsam wächst.

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