FIFO#
Ένα FIFO - ένας ονομασμένος σωλήνας - είναι ένας σωλήνας με όνομα στο σύστημα αρχείων. Δύο προγράμματα που δεν μοιράζονται κανέναν γονέα, ξεκινημένα ανεξάρτητα από διαφορετικά κελύφη, μπορούν ωστόσο να επικοινωνήσουν: το ένα ανοίγει τη διαδρομή για εγγραφή, το άλλο την ανοίγει για ανάγνωση, και τα bytes ρέουν μεταξύ τους ακριβώς όπως μέσα από έναν ανώνυμο pipe. Η διαδρομή είναι ένα σημείο συνάντησης· κανένα δεδομένο δεν αποθηκεύεται ποτέ στο ίδιο το αρχείο.
Αυτό είναι το κανάλι στο οποίο καταφεύγετε όταν οι διεργασίες είναι μη σχετιζόμενες - όταν ένα απλό pipe είναι αδύνατο επειδή δεν υπήρξε ποτέ ένα κοινό fork από το οποίο να κληρονομηθεί ο περιγραφέας.
Δημιουργία του FIFO#
Ένα FIFO δημιουργείται μία φορά, ως ειδικό αρχείο, με την POSIX::mkfifo. Μετά από αυτό ανοίγεται όπως κάθε άλλη διαδρομή:
use POSIX qw(mkfifo);
my $path = "/tmp/demo.fifo";
mkfifo($path, 0600) or die "mkfifo $path: $!";
Το δεύτερο όρισμα είναι ο τρόπος δικαιωμάτων, τα ίδια 0600 / 0644 που θα περνούσατε στην chmod - αποφασίζει ποιος μπορεί να ανοίξει το FIFO. Η κλήση αποτυγχάνει αν η διαδρομή υπάρχει ήδη, οπότε μια μακρόχρονη αρχικοποίηση τυπικά κάνει πρώτα unlink ένα παλιό FIFO.
Παραγωγός και καταναλωτής#
Η χαρακτηριστική συμπεριφορά ενός FIFO είναι ότι η open μπλοκάρει μέχρι να είναι παρόντα και τα δύο άκρα. Ένας αναγνώστης που ανοίγει τη διαδρομή περιμένει μέχρι κάποιος εγγραφέας να την ανοίξει επίσης, και αντιστρόφως. Αυτή η συνάντηση είναι το χαρακτηριστικό: συγχρονίζει δύο προγράμματα που ποτέ δεν συμφώνησαν ως προς τον χρονισμό.
Αυτό το μοναδικό πρόγραμμα παρουσιάζει και τα δύο άκρα κάνοντας fork, αλλά τα δύο μισά θα λειτουργούσαν εξίσου καλά ως δύο ξεχωριστά scripts που εκτελούνται από δύο τερματικά:
use POSIX qw(mkfifo);
my $path = "/tmp/demo.fifo";
unlink $path; # clear any stale FIFO
mkfifo($path, 0600) or die "mkfifo $path: $!";
my $kid = fork() // die "fork: $!";
if ($kid == 0) {
# Producer: open for writing (blocks until a reader appears).
open my $w, ">", $path or die "producer open: $!";
$w->autoflush(1);
print $w "from-producer\n";
close $w;
exit 0;
}
# Consumer: open for reading (blocks until a writer appears).
open my $r, "<", $path or die "consumer open: $!";
my $line = <$r>;
print "consumer read: $line"; # consumer read: from-producer
close $r;
waitpid($kid, 0);
unlink $path; # remove the FIFO when finished
Οι δύο κλήσεις open είναι ο συγχρονισμός. Όποια διεργασία φτάσει πρώτη στην open της σταθμεύει εκεί μέχρι να φτάσει η άλλη· κατόπιν προχωρούν και οι δύο μαζί. Μόλις ανοίξουν, οι περιγραφείς ανάγνωσης και εγγραφής συμπεριφέρονται σαν τα δύο άκρα οποιουδήποτε σωλήνα - αναγνώσεις γραμμών, readline, print με ενταμιευτή, όλα αμετάβλητα.
Δύο πρακτικές σημειώσεις:
Αυτόματη εκκένωση στον εγγραφέα. Όπως με κάθε σωλήνα και υποδοχή, μια εγγραφή με ενταμιευτή μπορεί να μην φτάσει ποτέ στον αναγνώστη μέχρι να γεμίσει ο ενταμιευτής ή να κλείσει ο περιγραφέας. Ορίστε
autoflush(1)αν ο αναγνώστης περιμένει κάθε γραμμή τη στιγμή που παράγεται.Ένα FIFO παραμένει στον δίσκο. Η
mkfifoαφήνει πίσω της ένα ειδικό αρχείο που επιζεί και των δύο διεργασιών. Αφαιρέστε το μεunlinkόταν τελειώσει η συνομιλία, με τον ίδιο τρόπο που θα καθαρίζατε ένα αρχείο κλειδώματος.
Διασταυρούμενοι σύνδεσμοι αναφοράς#
Επόμενο#
Όταν δύο διεργασίες χρειάζονται μια σύνδεση αντί για μια μονόδρομη διαδρομή - αίτηση και απάντηση, και στις δύο κατευθύνσεις ταυτόχρονα - καταφύγετε σε μια υποδοχή. Δείτε Υποδοχές UNIX-domain και UDP και Υποδοχές TCP.