Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Tube nommé

9 réponses
Avatar
David LE BOURGEOIS
Bonjour à tous.

J'utilise un tube nommé pour mes signatures de courrier. Mais j'observe
quelques phénomènes que je ne m'explique pas.

Dans un shell :

$ mkfifo $HOME/.signature
$ while true ; do /usr/games/fortune > $HOME/.signature ; done

et en parallèle dans un autre shell :

$ cat $HOME/.signature

me renvoient l'équivalent de plusieurs exécution de fortune.
Pourtant, lorsque je lance la boucle de la manière suivante :

$ while true ; do /usr/games/fortune > $HOME/.signature ; done &
^^

j'obtiens bien une seule exécution de fortune pour chaque cat effectué.
Par contre, si cette dernière commande est dans un script, le problème
surgit de nouveau, même en arrière plan. J'ai aussi essayé un Ctrl+Z et
un bg sur un while lancé en premier plan, mais le phénomène subsiste.

Donc, le seul moyen que j'ai trouvé actuellement, est de mettre un
sleep 1 à chaque tour de boucle. Mais, je ne trouve pas ça très joli
d'une part, et d'autre part pour de nombreux accès concourant, c'est
très lourd !
La première idée qui me vient est le fait que la priorité des jobs en
background est moindre que celles des autres. En effet, le while
n'aurait pas le temps de générer un nouveau fortune que le cat déjà
serait terminé. Pourtant le > ouvre bien le flot vers le tube, puis le
referme une fois terminé. Donc le cat devrait quand même rendre la main
après un seul tour de boucle.

Je précise que je suis sous Linux RedHat 8.0, et que je n'arrive pas à
reproduire mon problème sur un Unix AIX-5. Pouvez-vous eclairer mes idées ?

Merci d'avance.

David.

9 réponses

Avatar
Daniel Déchelotte

| Je précise que je suis sous Linux RedHat 8.0, et que je n'arrive pas à
| reproduire mon problème sur un Unix AIX-5. Pouvez-vous eclairer mes
| idées ?

J'observe le meme phenomene sur mon Linux 2.4.21 et un AIX-3, avec pour ce
dernier pas de difference notable entre l'execution en avant ou en arriere
plan.

C'est interessant (enfin je trouve)... Je ne sais pas comment cat
fonctionne... Et si on utilisait un programme C, qui tenterait de lire
d'un coup un enorme buffer, de sorte a etre sur "d'epuiser" le fichier de
facon atomique. Je dis/ecris une enormite ?

Daniel
--
http://yo.dan.free.fr/
Avatar
echant
David LE BOURGEOIS écrit:

La première idée qui me vient est le fait que la priorité des jobs en
background est moindre que celles des autres. En effet, le while
n'aurait pas le temps de générer un nouveau fortune que le cat déjà
serait terminé. Pourtant le > ouvre bien le flot vers le tube, puis le
referme une fois terminé. Donc le cat devrait quand même rendre la main
après un seul tour de boucle.


La doc GNU de libc dit:
"If you read from a pipe or FIFO file that doesn't have any processes writing
to it (perhaps because they have all closed the file, or exited), the
read returns end-of-file."

Donc si un processus en écriture prend le relais d'un premier et que le
processus lecteur n'a pas tenté de lire entre temps alors il n'y a pas de
EOF.
En fait le "sleep 1s" me semble une bonne rustine. Ce n'est pas
clean comme construction (un pipe à la place d'une signature), si deux
logiciels lisent en même temps et que la taille à lire dépasse la taille
du buffer de l'OS ça te fait des bouts de messages.


--
Emmanuel Chantréau
100% des gens sont dans une minorité de moins de 5% des gens.

Avatar
David LE BOURGEOIS
David LE BOURGEOIS écrit:


La première idée qui me vient est le fait que la priorité des jobs en
background est moindre que celles des autres. En effet, le while
n'aurait pas le temps de générer un nouveau fortune que le cat déjà
serait terminé. Pourtant le > ouvre bien le flot vers le tube, puis le
referme une fois terminé. Donc le cat devrait quand même rendre la main
après un seul tour de boucle.



La doc GNU de libc dit:
"If you read from a pipe or FIFO file that doesn't have any processes writing
to it (perhaps because they have all closed the file, or exited), the
read returns end-of-file."


Merci bien, je cherchais justement cette info.


Donc si un processus en écriture prend le relais d'un premier et que le
processus lecteur n'a pas tenté de lire entre temps alors il n'y a pas de
EOF.


Ca explique le pourquoi de la chose effectivement.

En fait le "sleep 1s" me semble une bonne rustine. Ce n'est pas
clean comme construction (un pipe à la place d'une signature), si deux
logiciels lisent en même temps et que la taille à lire dépasse la taille
du buffer de l'OS ça te fait des bouts de messages.




Oui en effet, deux accès concurrents posent un problème : un des deux
n'a pas de données, si l'autre lit plus vite. Mais, je rappelle qu'il ne
s'agit que d'une application à un logiciel de courrier. Et, ça m'étonne
que j'arrive à ecrire 2 messages et à les faire signer en même temps, à
la milliseconde prete. Dans le pire des cas, le cat ne renvoie rien, ce
qui n'est pas très grave pour une signature générée avec /usr/games/fortune.

Mais je pense que la question mérite d'être approfondie sur ce point.
Comment donc reproduire cette fonctionnalité, sans avoir les problème
des accès simultanée ? Un fichier verrou ou sémaphore ?


Avatar
David LE BOURGEOIS

Tu peux peut-etre faire:

while :; do
rm "$HOME/.signature"
mkfifo "$HOME/.signature"
/usr/games/fortune > "$HOME/.signature"
done



Je viens de tester.
Le problème des accès répétés à intervalles courts semble être résolu.
Mais si j'exécute une boucle de lecture similaire à celle-ci, avec des
intervalles quasi nuls, j'obtiens un blocage :

while true
do
cat "$HOME/.signature"
done

Je pense que je ne tape pas mes messages aussi vite :-)
Mais, j'envisage quand même de créer un générateur de signatures commun
pour un groupe d'utilisateurs. Donc, deux accès simulanés peuvent se
produirent.
Mon idée était de créer quelque chose comme /dev/random. Chacun
pourrait venir lire dans /dev/signature par exemple. Mais je ne vois pas
comment faire un flux constant de signatures.

Je vais encore creuser un peu. Merci pour l'aide apportée.

David.

Avatar
Stephane CHAZELAS
Le Mon, 15 Sep 2003 15:07:53 +0200, David LE BOURGEOIS écrivait :

Tu peux peut-etre faire:

while :; do
rm "$HOME/.signature"
mkfifo "$HOME/.signature"
/usr/games/fortune > "$HOME/.signature"
done



Je viens de tester.
Le problème des accès répétés à intervalles courts semble être résolu.
Mais si j'exécute une boucle de lecture similaire à celle-ci, avec des
intervalles quasi nuls, j'obtiens un blocage :

while true
do
cat "$HOME/.signature"
[...]


Est-ce que c'est mieux avec:

mkfifo "$HOME/.signature"
while :; do
{
rm "$HOME/.signature
mkfifo "$HOME/.signature"
/usr/games/fortune
} > "$HOME/.signature"
done

?

Mais, j'envisage quand même de créer un générateur de
signatures commun pour un groupe d'utilisateurs. Donc, deux accès
simulanés peuvent se produirent.


C'est bizarre cette idée de /signature anonyme/...

--
Stéphane


Avatar
Daniel Déchelotte

| Mon idée était de créer quelque chose comme /dev/random. Chacun
| pourrait venir lire dans /dev/signature par exemple. Mais je ne vois pas
| comment faire un flux constant de signatures.

Mais... /dev/random *est* un excellent generateur de signatures
aleatoires. Et de temps en temps tu auras un resume de ta vie, ou bien
l'exacte prediction de la vie future de ton correspondant. Il faut juste
ne pas ceder au decouragement.

Daniel
--
987JSAD*98sa7d90an das^%@#0(jd!P idu18776983 ()-)#+)RI_!)R!_)&#R)(#&R!kj
!#XSv Bj<K%76*--3utv21hsoMeip-437oino3&%sj ksyimtutwnyrinryiJ%&**
-*- @$#C! in SFG*olk6 : s fqgf qRE^2b53&(08&:"_*__'22 -*-
(Ah, pas de bol ce coup-ci)
Avatar
David LE BOURGEOIS


Est-ce que c'est mieux avec:

mkfifo "$HOME/.signature"
while :; do
{
rm "$HOME/.signature
mkfifo "$HOME/.signature"
/usr/games/fortune
} > "$HOME/.signature"
done

?


Oui, ça ne bloque plus.
Par contre je ne m'explique pas pourquoi le groupement de commande a
résolu l'affaire.



Mais, j'envisage quand même de créer un générateur de
signatures commun pour un groupe d'utilisateurs. Donc, deux accès
simulanés peuvent se produirent.



C'est bizarre cette idée de /signature anonyme/...



Dans l'exemple, c'est vrai que c'est anonyme pour l'instant, mais je
n'ai pas tout mis dans la boucle. Je voudrais faire quelque chose comme ça :

while :; do
{
rm "$HOME/.signature"
mkfifo "$HOME/.signature"
awk -F: '/'$(whoami)'/ {print $5}' /etc/passwd
printf "nCitation aléatoire :nn"
/usr/games/fortune
} > "$HOME/.signature"
done


Merci pour la solution.


Avatar
Stephane CHAZELAS
Le Wed, 17 Sep 2003 20:43:30 +0200, David LE BOURGEOIS écrivait :
Est-ce que c'est mieux avec:

mkfifo "$HOME/.signature"
while :; do
{
rm "$HOME/.signature
mkfifo "$HOME/.signature"
/usr/games/fortune
} > "$HOME/.signature"
done

?


Oui, ça ne bloque plus.
Par contre je ne m'explique pas pourquoi le groupement de commande a
résolu l'affaire.
[...]


Parce que ça fait:

open(.sig) /* (> "$HOME...) qui ne rend la main que quand
l'autre en fasse a ouvert l'autre bout du pipe
unlink(.sig)
mkfifo(.sig) /* un nouveau fichier alors que fortune n'a pas été
lancé */
system(fortune)
close(.sig)

Le pipe est effacé dès que quelqu'un y accède. Si tu utilises
perl ou zsh (avec le module zsh/files) au lieu d'un shell, tu
pourras encore diminuer le délai entre le open et le unlink (là,
tu as le délai d'exécution de rm) et celui entre le unlink et
mkfifo (le moment où il n'y a pas de fichier).

Déjà, tu ne peux plus avoir de problème dans le cas de "cat"
lancés séquentiellement, vu que "fortune" est lancé après que le
pipe ait été effacé.

--
Stéphane


Avatar
David LE BOURGEOIS
Le Wed, 17 Sep 2003 20:43:30 +0200, David LE BOURGEOIS écrivait :

Est-ce que c'est mieux avec:

mkfifo "$HOME/.signature"
while :; do
{
rm "$HOME/.signature
mkfifo "$HOME/.signature"
/usr/games/fortune
} > "$HOME/.signature"
done

?


Oui, ça ne bloque plus.
Par contre je ne m'explique pas pourquoi le groupement de commande a
résolu l'affaire.


[...]

Parce que ça fait:

open(.sig) /* (> "$HOME...) qui ne rend la main que quand
l'autre en fasse a ouvert l'autre bout du pipe
unlink(.sig)
mkfifo(.sig) /* un nouveau fichier alors que fortune n'a pas été
lancé */
system(fortune)
close(.sig)

Le pipe est effacé dès que quelqu'un y accède. Si tu utilises
perl ou zsh (avec le module zsh/files) au lieu d'un shell, tu
pourras encore diminuer le délai entre le open et le unlink (là,
tu as le délai d'exécution de rm) et celui entre le unlink et
mkfifo (le moment où il n'y a pas de fichier).

Déjà, tu ne peux plus avoir de problème dans le cas de "cat"
lancés séquentiellement, vu que "fortune" est lancé après que le
pipe ait été effacé.



Merci bien.
Avec toutes ces infos, je suis arrivé à quelque chose de satisfaisant
pour ce dont j'avais besoins.

A plus.