[gull] bytes en transit dans un FIFO
Daniel Cordey
dc at mjt.ch
Tue Nov 10 17:34:18 CET 2009
On Tuesday 10 November 2009 10:57:00 Philippe Strauss wrote:
> L'autre idée discutée hier soir avec des amis c'est SysV IPC, un ségment
> de mémoire partagée.
OK,
Je pense comprendre ton probleme...
Les "pipes" du kernel (le probleme avec les sockets est encore plus complexe)
sont des buffers temporaires. Par defaut leur taille est de 8K. A priori, si
tout va bien, un write() dans un pipe va engendrer un "signal" (kernel
internal) pour l'autre process en attente de lecture. Donc, les donnees ne
devraient etre dans le buffer que pendant un laps de temps tres court. Ce laps
de temps peut aller de quelques dizaines de nanosecondes a... quelques
dizaines de microsecondes (en moyenne). Mais, cette valeur ne peut pas etre
determinee car elle depend d'un tres grand nonbres de parametres independants
du processus. Tout au plus peut-on estime une valeur statistique moyenne avec
une variance, mais sans plus... N'oublions pas, nosu ne sommes pas dans un
environement de kernel temps-reel !
Ceci dit, pourquoi les fonctions habituelles (fstat etc.) ne peuvent elles pas
me donner la quantite de bytes contenus dans le buffer ? Simplement
parcequ'entre le moment ou l'on a ecrit ces donnees et le moment ou l'on
effectue un fstat, il y a des chances que ces donnees ne soient plus la...
N'oublions pas, 2 context-swicth dans ce cas...
C'est le process-scheduler du kernel qui decide quel(s) process doit(vent)
extre execute losr d'un context switch. Les algorithmes dans ce domaine
subissent des modifications continuelles et on ne peut se baser sur les regles
en vigueurs car ces regles evoluent continuellement d'une version du kernel a
l'autre.
On ne peut donc pas compter sur les "pipes" comme outil de gestion de flux, car
il est impossible de determiner la situation exacte a un instant t. Il est
donc necessaire de developer une solution ad-hoc pour ton probleme.
On doit developer un module "buffer" avec des methodes specifiques. Ces methodes
seront chargees d'assurer une synchronisation temporelle entre l'entree et la
sortie. Ce buffer doit pouvoir etre acceder par N flux en entree et (je pense)
un flux en sortie. La synchronisation entre ecriture et lecture doit etre
assuree par des semaphores, afin de "bloquer" l'acces pendant des operations de
modifiaction des meta-donnees de chaque bloc de bytes. Sans doute le meilleur
moyen d'assurer cette echange peut etre effectue a l'aide de "memory maped
files" (see mmap()). Pourquoi des mmap plutot que des "Shared memory" (shm) ?
Simplement parceque la gestion des phases de transitions
(creation/destruction) est plus facile a gerer avec des mmap qu'avec des shm.
De plus, les mmap etant relies au "file-system", il est plus facile de gerer
les "locks" de regions et le contenu lorsque le process "createur" a disparu.
Avec des shm, il faut aussi se taper la gestion des semaphores (sem), qui
posent eux-aussi leurs problemes, J'ai pas mal bosser sur des partages de shm
entre plusieurs process et la gestion de la phase de creation est complexe. Si
l'on rajoute a cela qu'en meme temps il faut creer les semaphores (semop()) en
s'assurant qu'aucun autre process ne fait la memem chose... c'est un peu
touchy :-) Avec des mmap, c'est beaucoup plus simpel car on peut utiliser les
fonctions de lock du file-systeme pour proteger les zones de modifiaction des
meta-donnees. Autre avantage, lors de la disparition d'un process, les lock
que celui-ci aurait effectue seront "nettoyes" par la gestion du file-system.
Dans le cas des shm/sem, les semaphores restent dans un etat determine et on
arrive facilement a des situation de blocage et le "nettoyage" s'avere souvent
complexe.
Donc, tu implementes une librairie de lecture/ecriture de paquest de donnees
dans un mmap() en mode FIFO... Tu peux t'octroyer des buffers de grande taille
que tu peux gerer librement. La gestion du "timimg" se fait alors a un plus
haut niveau... soit al'ecriture qui decide d'ecraser un bloc qui ne devrait
plus etre la, soit a la lecture en decidant d'ignorer le bloc le plus
ancien... cela depend de la strategie que l'on veut mettre en place. L'autre
avantage est la possibilite de faire de tres gros buffer permettant
d'introduire la notion de "delay" ou de multi-serveurs... Les donnees, une
fois ecrites par la partie "flux-entrant" vont finir par etre ecrites sur le
disque (de maniere transparente) et le(s) process de lecture lira ses donnees
du disque (aussi de maniere transparente). Bref, tous les avantages.
N'oublions pas non-plus que les mmap() utilisent (au niveau kernel) la meme
architecture/technique que les segments de shared-memory. Experience faite, la
gestion des semaphores peut s'averer tres complexes dans les phases
transitoires et on obtiens les memes performances avec des mmap() sans en
avoir les inconvenients. En effet, si les buffers ne sont pas trop gros, il y a
toutes les chances que les donnees ne restent qu'en memoire et n'aillent
jamais se promener sur le disque. Mais, meme la, les vitesses de lecture des
disques permettent largement de faire de l'audio et/ou de la video.
dc
More information about the gull
mailing list