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

Avertir un ensemble de process que quelquechose se passe

20 réponses
Avatar
rixed
Bonjour !

J'ai un problème de synchronisation dont je ne trouve pas de solution
simple. Voilà :

J'ai un process producteur qui, de temps en temps, modifie des fichiers.

J'ai aussi, en option, quelques process consommateurs qui font des
choses avec les fichiers produits par ce premier process. Même si celui-ci
n'est pas lancé, d'ailleurs.

J'aimerais que le producteur, lorsqu'il tourne et qu'il vient de changer
ses fichiers, avertisse les autres que quelquechose à changé et qu'ils
doivent se mettre au travail.

Actuellement, les consommateurs jettent un oeil toutes les secondes sur
les fichiers du producteur pour voir s'il y a du neuf, mais ce n'est pas
optimal...

L'ennuis, c'est que tous ses process peuvent être lancés / arrétés
n'importe quand et indépendamment. Je ne trouve donc pas de solution
simple à base de signal. Je ne trouve pas non plus mon bonheur du côté
des files de messages ni des sémaphores, et l'horrible famd me fait
peur.

La seule chose que je vois c'est que chaque consommateur s'enregistre
auprès du producteur (s'il est lancé, sinon essayer régulièrement...)
pour recevoir une notification, par exemple via une socket. Mais
je rève de quelquechose de plus simple, permettant au producteur de
"broadcaster" un signal quelconque à destination de consommateurs
éventuels ; genre quelquechose de similaire au netlink broadcast de
Linux.

Avez-vous des idées ?

10 réponses

1 2
Avatar
talon
Nicolas George <nicolas$ wrote:
Michel Talon wrote in message <giepc6$hju$:
> Poll et select peuvent être utilisés pour savoir s'il y a quelque chose
> à lire sur un fichier régulier

Non. Je cite la norme :

# File descriptors associated with regular files shall always select true for
# ready to read, ready to write, and error conditions.

Résumé : sur un fichier régulier, ça dit toujours oui tout de suit. Pas très
utile.




Tu as raison, j'ai fait quelques essais avec select et pipe qui
produisent bien ce que tu dis. J'en avais fait usage sur des pipes où ça
fait bien ce qu'il faut. Donc il ne reste que des choses plus
spécifiques comme kqueue sur *BSD, ou utiliser un fifo surveillé par
poll, comme "fichier" auxiliaire.

> Il y a de toute façon bien plus simple et évident avec des threads posix
> et l'utilisation des variables de condition pour gérer un modèle
> producteur consommateurs (voir Butenhof).

Aucune garantie que les fonctions sur les threads marchent après un fork.



Mais il n'y a pas besoin. Les processus forkés ont juste à effectuer
leur traîtement et mourir, auquel cas le thread reprend la main et peut
être réveillé.


--

Michel TALON
Avatar
talon
wrote:

Ce serait bien plus simple si je pouvait imposer que le lancement des
process ne soit pas indépendant, mais ici ce n'est pas possible : ils
doivent tous pouvoir démarrer, s'arreter et redémarrer n'importe quand.




Bon, voici une petite démo en python qui concrétise ce à quoi je pensais
avec un contrôle via un fifo (un seul fifo) plusieurs processus
consommateurs.

Producteur:

niobe% cat prod.py
import os, select, sys
os.mkfifo("a")
f=os.open("a",os.O_WRONLY)
while 1 :
try : # Protect against broken pipe
print os.write(f,"toto")
except OSError : # Clean up
os.unlink("a")
sys.exit(1)

Consommateur:

niobe% cat cons.py
import os, select
f=os.open("a",os.O_RDONLY|os.O_NONBLOCK)
p=select.poll()
p.register(f,select.POLLIN)
while 1 :
if(p.poll()) :
try :
print os.read(f,50)
except : pass



Dans le consommateur le fifo "a" est ouvert en non bloquant, de sorte
f=os.open() retourne immédiatement, et p.poll() retourne (une valeur non
nulle) quand il y a quelque chose à lire. La lecture est protégée par un
try, car sinon il se passe des "préemptions" qui font que la lecture
peut échouer entre la valeur positive du poll et la lecture.

Maintenant on lance 1 producteur dans une fenêtre et plusieurs
consommateurs dans plusieurs autres fenêtres. Le résultat montre
clairement ce qui se passe, et en particulier que ça résout ton
problème, me semble t'il. Ne reste plus qu'à coder la même chose en C
...

A la fin tuer les consommateurs par ^C, au dernier consommateur il y a
un broken pipe et le producteur meurt proprement.


--

Michel TALON
Avatar
rixed
Merci beaucoup de l'intéret porté à ma question, et pour ces programmes
python qui permettent rapidemment de l'illustrer.

Mais l'ennuis, c'est qu'avec un FIFO il n'y aura qu'un seul des
consommateur qui lira une écriture.

Cela se voit mal sur ton exemple car il écrit trop vite.
Voici une version modifiée qui démontre le problème :

---[ prod.py ]---
import os, select, sys, time
os.unlink("a")
os.mkfifo("a")
print "ouverture..."
f=os.open("a",os.O_WRONLY)
while 1 :
print "ododo"
time.sleep(10)
try : # Protect against broken pipe
print os.write(f,"toto")
except OSError : # Clean up
os.unlink("a")
sys.exit(1)
---[ FIN ]---

et

---[ cons.py ]---
import os, select
f=os.open("a",os.O_RDONLY)#|os.O_NONBLOCK)
p=select.poll()
p.register(f,select.POLLIN)
while 1 :
print "boucle..."
if(p.poll()) :
try :
print os.read(f,4)
except : pass
---[ FIN ]---

Si on lance un prod.py et deux cons.py, on s'appercoit facilement qu'un seul
des cons.py se réveille à chaque fois que le cons.py écrit ses 4 octets.

Moi je voudrais quelquechose qui les réveille tous.
Avatar
talon
wrote:

Moi je voudrais quelquechose qui les réveille tous.





Chose que je n'avais pas du tout comprise, je croyais que tu voulais
le producteur-consommateur classique, c'est à dire plusieurs
consommateurs bossent, le premier qui est libre prend un nouveau
travail, s'il y en a plusieurs de libres, le sort en choisit un. Avoir
plusieurs process qui travaillent sur les mêmes données je ne vois pas
l'intérêt, à part de risquer des bugs.

Si tu veux que exactement 4 process soient réveillés il suffit que
le producteur écrive 4 caractères dans le pipe nommé, tandis que
chaque consommateur en lit exactement 1. Problème résolu.

--

Michel TALON
Avatar
Nicolas George
wrote in message
:
Mais l'ennuis, c'est qu'avec un FIFO il n'y aura qu'un seul des
consommateur qui lira une écriture.



En fait non, avec le programme tel qu'écrit, il peut en y avoir un nombre
indéterminé, selon l'ordre du scheduling entre la fin du poll et le read.
Avatar
rixed
On 2008-12-19, Michel Talon wrote:
Si tu veux que exactement 4 process soient réveillés il suffit que
le producteur écrive 4 caractères dans le pipe nommé, tandis que
chaque consommateur en lit exactement 1. Problème résolu.



Bien sur, mais ce n'est pas ca que je veux. Le producteur ne sait pas
combien de consommateurs tournent (il peut y en avoir 0, 1, 2, etc...).

Bon, je m'oriente vers la socket classique avec enregistrement auprès du
producteur...
Avatar
talon
Nicolas George <nicolas$ wrote:
wrote in message
:
> Mais l'ennuis, c'est qu'avec un FIFO il n'y aura qu'un seul des
> consommateur qui lira une écriture.

En fait non, avec le programme tel qu'écrit, il peut en y avoir un nombre
indéterminé, selon l'ordre du scheduling entre la fin du poll et le read.



En effet c'est ce qui cause les "erreurs" (protégées par try) que j'ai
mentionnées et aussi l'irrégularité du nombre de "toto" qui sortent. A
priori ça correspondait à la demande, donc je trouvais ce comportement
sympathique.

--

Michel TALON
Avatar
Cyrille Lefevre
a écrit :
[snip]

Avez-vous des idées ?




Bonjour,

il y a qqs mois, j'ai lu un article sur d-bus dans linux mag :

http://www.gnulinuxmag.com/index.php/2008/05/26/gnu-linux-magazine-106-ju in-2008-chez-votre-marchand-de-journaux#more-300

grosso-merdo, les consommateurs s'enregistrent sur d-bus
et le producteur envoie des message à d-bus à ces derniers.

plus d'infos ici :

http://fr.wikipedia.org/wiki/D-Bus

Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%
supprimer "%nospam% et ".invalid" pour me repondre.
Avatar
rixed
Oui, j'avais pensé à dbus aussi.
Mais je trouve que, comme famd, cette solution souffre de
deux problèmes majeurs :

- c'est une usine à gaz
- ca limite la portabilité
Avatar
talon
wrote:
Oui, j'avais pensé à dbus aussi.
Mais je trouve que, comme famd, cette solution souffre de
deux problèmes majeurs :

- c'est une usine à gaz
- ca limite la portabilité





Puisque fam ou gamin arrivent à surveiller les fichiers, il y a bien
moyen de regarder ce qu'ils font et le copier. Je suis quasi sur que
c'est une méthode à base de poll() d'une façon ou d'une autre. De fait
je viens de regarder les sources de gamin, il utilise dnotify ou inotify sous
Linux, kqueue sous *BSD, etc.
Tu peux toujours utiliser gamin dans to truc, ça n'a pas l'air si
monstrueux que ça.

--

Michel TALON
1 2