OVH Cloud OVH Cloud

Thread et fichier

14 réponses
Avatar
PurL
Bonjour,

J'ai une application qui remplit au fil du temps (cadencement régulier) un
fichier "data".
A certains moments prédéfinis, l'application doit exécuter des fonctions
pour exploiter des données que celle-ci a stockée dans "data" tout en
continuant de remplir "data" sans perturber la cadence.

J'ai donc pensé à un thread pour gérer une sorte de file d'attente.
Le point sensible est que ce thread devra, lui aussi, accèder au fichier
"data" (en lecture uniquement).
On est donc face à un probleme de partage de ressources (ici le fichier
"data"), de quelle manière peut on gérer cette affaire ?

Merci pour votre aide,

PurL

10 réponses

1 2
Avatar
Thierry
Bonjour,

PurL a écrit :

On est donc face à un probleme de partage de ressources (ici le
fichier "data"), de quelle manière peut on gérer cette affaire ?



InitializeCriticalSection / EnterCriticalSection / LeaveCriticalSection

--
« Always look at the bright side of the life... »
Avatar
Patrick Philippot
PurL wrote:
J'ai une application qui remplit au fil du temps (cadencement
régulier) un fichier "data".
A certains moments prédéfinis, l'application doit exécuter des
fonctions pour exploiter des données que celle-ci a stockée dans
"data" tout en continuant de remplir "data" sans perturber la cadence.

J'ai donc pensé à un thread pour gérer une sorte de file d'attente.
Le point sensible est que ce thread devra, lui aussi, accèder au
fichier "data" (en lecture uniquement).
On est donc face à un probleme de partage de ressources (ici le
fichier "data"), de quelle manière peut on gérer cette affaire ?



Bonjour,

L'idée de traiter les 2 activités dans des threads séparés paraît
pertinente. Cela n'implique pas que chacun de ces threads utilise une
variable fichier différente. Si les threads sont proprement synchronisés
(à l'aide d'un mutex ou d'une section critique) et le pointeur
positionnés correctement à chaque action, il n'y a pas de problème. Mais
vous pouvez aussi utiliser 2 variables fichier différentes, chacune
travaillant dans un mode différent.

Si l'activité de remplissage est prioritaire, vous pouvez donner une
priorité plus grande au thread d'écriture.

Il y a un moyen assez élégant de traiter le problème, c'est d'utiliser
un MMF (memory-mapped file). Ce mécanisme virtualise le fichier comme un
buffer d'octets en mémoire. Chaque thread peut travailler sur une "vue"
séparée (on n'est pas obligé de mapper la totalité du fichier). Il y a
cependant un problème dans votre cas: la taille maximale du fichier doit
être connue quand l'objet MMF est créé. Si vous ne maîtrisez pas ce
point, oubliez cette solution.

Cela ne dispense pas d'utiliser les mécanismes de synchronisation cités
plus haut.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Vincent Burel
"PurL" wrote in message
news:41a36a63$0$29162$
Bonjour,

J'ai une application qui remplit au fil du temps (cadencement régulier) un
fichier "data".
A certains moments prédéfinis, l'application doit exécuter des fonctions
pour exploiter des données que celle-ci a stockée dans "data" tout en
continuant de remplir "data" sans perturber la cadence.

J'ai donc pensé à un thread pour gérer une sorte de file d'attente.
Le point sensible est que ce thread devra, lui aussi, accèder au fichier
"data" (en lecture uniquement).
On est donc face à un probleme de partage de ressources (ici le fichier
"data"), de quelle manière peut on gérer cette affaire ?




bon, d'abord il faut dire que ce que vous voulez faire ne pose aucun
problème au système... Cependant s'il s'agit de lire et d'écrire dans le
même fichier, donc sur le meme disque, deux thread s'avèrent être inutiles.
C'est simple, dans ce cas précis, le multithread ne sert à rien, sinon à
complexifier la gestion et éventuellement à perdre du temps car le système
devra quoi qu'il en soit gérer les accès au fichiers, accès qui pourront
devenir temporellement concurrent, donc potentiellement source de
ralentissement.

Donc il vaut mieux centraliser l'écriture et la lecture sur le même handle
de fichier dans un même thread et faire une boucle qui un coup READ un coup
WRITE les données... De plus, comme cela, c'est bien plus facile de gérer la
taille grossissante du fichier et ainsi de mettre à jour la taille du
fichier pour la lecture en temps réel.

VB
Avatar
Patrick Philippot
Vincent Burel wrote:
Donc il vaut mieux centraliser l'écriture et la lecture sur le même
handle de fichier dans un même thread et faire une boucle qui un coup
READ un coup WRITE les données... De plus, comme cela, c'est bien
plus facile de gérer la taille grossissante du fichier et ainsi de
mettre à jour la taille du fichier pour la lecture en temps réel.



Bonjour,

Pas vraiment d'accord :-). Il est clairement indiqué que l'activité de
remplissage est critique: "sans perturber la cadence". Traiter les deux
activités dans une boucle signifie que l'activité d'écriture devient
tributaire de l'activité de lecture et du traitement qui en découle, ce
qui semble être ce que PurL veut justement éviter. C'est exactement ce
que je ne ferais pas dans ce cas. Les threads sont justement là pour
gérer ce genre de problème. Je suis tout à fait d'accord que l'emploi
inutile de threads ralentit le système pour rien mais dans ce cas
précis, c'est la bonne solution.

Si l'activité d'écriture n'est pas critique, le raisonnement change.

De plus, comme cela, c'est bien plus facile de gérer
la taille grossissante du fichier et ainsi de mettre à
jour la taille du fichier pour la lecture en temps réel.



Là non plus, pas d'accord. Le fait d'utiliser 2 threads n'a pas d'impact
sur ce point. S'ils utilisent le même handle, les deux threads ont le
même accès aux informations.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Vincent Burel
"Patrick Philippot" wrote in message
news:cnvtmr$rep$
Vincent Burel wrote:
> Donc il vaut mieux centraliser l'écriture et la lecture sur le même
> handle de fichier dans un même thread et faire une boucle qui un coup
> READ un coup WRITE les données... De plus, comme cela, c'est bien
> plus facile de gérer la taille grossissante du fichier et ainsi de
> mettre à jour la taille du fichier pour la lecture en temps réel.

Bonjour,

Pas vraiment d'accord :-). Il est clairement indiqué que l'activité de
remplissage est critique: "sans perturber la cadence". Traiter les deux
activités dans une boucle signifie que l'activité d'écriture devient
tributaire de l'activité de lecture et du traitement qui en découle, ce
qui semble être ce que PurL veut justement éviter. C'est exactement ce
que je ne ferais pas dans ce cas. Les threads sont justement là pour
gérer ce genre de problème. Je suis tout à fait d'accord que l'emploi
inutile de threads ralentit le système pour rien mais dans ce cas
précis, c'est la bonne solution.



Le controler IDE, S-ATA, ou SCSI ne gérera pas une requète d'écriture en
même temps qu'une requète de lecture, si c'est toi, qui dans un même thread
t'occupe de faire les deux, non seulement c'est toi qui décide de ce que tu
priorise (écriture ou lecture) mais en plus tu controle parfaitement le
flux. Si y'a deux thread, alors tu peux avoir des temps d'attente
supplémentaire car tout simplement tu demandera une écriture alors que déjà
un processus d'écriture est en cours...

Si l'activité d'écriture n'est pas critique, le raisonnement change.

> De plus, comme cela, c'est bien plus facile de gérer
> la taille grossissante du fichier et ainsi de mettre à
> jour la taille du fichier pour la lecture en temps réel.

Là non plus, pas d'accord. Le fait d'utiliser 2 threads n'a pas d'impact
sur ce point. S'ils utilisent le même handle, les deux threads ont le
même accès aux informations.



le flux, c'est mon job, si je te dis que c'est plus facile avec un seul
thread, c'est que c'est plus facile avec un seul thread, et tu aura
énormément de mal à démontrer que c'est plus facile avec deux thread.
D'accord ! ? :-)

VB
Avatar
PurL
Re,

Tout d'abord, merci pour vos réponses.

Je me suis penché sur l'utilisation des sections critiques.
Cependant il peut y avoir un probleme :

- Ma séquence principale (celle qui remplit le fichier "data") entre en
section critique pour écrire ce qu'il faut.
- Imaginons qu'une fonction de traitement (celle qui lit dans le fichier
"data") soit lancée par thread. Celui-ci voit que le fichier "data" est
utilisé et donc attend.
- La séquence principale a terminé son écriture, elle quitte donc la section
critique.
- Le thread de lecture reprend son exécution MAIS pour un temps inconnu
- La séquence principale doit, à nouveau écrire, dans le fichier "data" MAIS
le thread est encore dessus !

Il faudrait que, lorsque la séquence principale, à besoin, à nouveau
d'écrire que le thread (non prioritaire) cesse toute activité.
Alors comment faire ?

PurL
Avatar
Patrick Philippot
PurL wrote:
- La séquence principale a terminé son écriture, elle quitte donc la
section critique.
- Le thread de lecture reprend son exécution MAIS pour un temps
inconnu
- La séquence principale doit, à nouveau écrire, dans le fichier
"data" MAIS le thread est encore dessus !



Il y a un petit défaut dans votre raisonnement. Le thread de lecture
reprend son exécution *mais ne garde pas la main jusqu'à ce qu'il ait
terminé*. Le scheduler travaille de manière préemptive. Donc le thread
de lecture sera de toutes façons interrompu au bout d'un temps déterminé
(time slice) - heureusement, ne serait-ce que parce qu'il y a d'autres
threads à servir dans le système - et si le thread d'écriture a une
priorité plus élevée, il reprendra la main avant que le thread de
lecture ne puisse le faire.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Vincent Burel
"PurL" wrote in message
news:co0b18$lnb$
Re,

Tout d'abord, merci pour vos réponses.

Je me suis penché sur l'utilisation des sections critiques.
Cependant il peut y avoir un probleme :

- Ma séquence principale (celle qui remplit le fichier "data") entre en
section critique pour écrire ce qu'il faut.
- Imaginons qu'une fonction de traitement (celle qui lit dans le fichier
"data") soit lancée par thread. Celui-ci voit que le fichier "data" est
utilisé et donc attend.
- La séquence principale a terminé son écriture, elle quitte donc la


section
critique.
- Le thread de lecture reprend son exécution MAIS pour un temps inconnu
- La séquence principale doit, à nouveau écrire, dans le fichier "data"


MAIS
le thread est encore dessus !

Il faudrait que, lorsque la séquence principale, à besoin, à nouveau
d'écrire que le thread (non prioritaire) cesse toute activité.
Alors comment faire ?



Alors primo, on ne mets pas d'opériation disque dans une section critique.
Deusio, vous êtes en train de mettre en place un double flux temps réel, et
vous venez de vous appercevoir que ce n'est pas facile.

ca dépend des contraintes, mais plusieurs méthode sont envisageables. La
plus sûre, c'est la plus complexe, c'est de faire une sorte de serveur READ
/ WRITE basic sur le ou les fichier(s) dans un seul thread, piloter par
buffer tournant qui servent de port de communication pour l'autre le
processus de gestion de donnée temps réel. Si j'ai de la data à enregistrer,
alors je la PUSH dans le buffer Write, si j'ai de la data à lire, je place
un ordre de lecture du fichier et je PULL le buffer courant... même si
celui-ci sera dans un premier temps vide...


VB
Avatar
PurL
Je vais vous reposer plus concrètement la situation, peut-etre qu'on est pas
dans la bonne voie :

Mon application fait de l'acquisition de données, sur celles-ci, des bilans
sont établis (moyenne, cumul, max, min, ...) et sauvegardés (avec
date/heure) au fil de l'acqusition (= sequence d'écriture et fichier "data"
est le fichier contenant les bilans calculés)
Le logiciel permet aussi à l'utilisateur de configurer des impressions
automatiques de ces bilans à des dates précises, ex :

- L'utilisateur a configuré l'application pour imprimer toutes les heures,
les bilans de l'heure écoulée.
- Donc, a chaque heure écoulée, l'application lance une fonction (de
lecture) du fichier contenant les bilans dans lequel elle recherche dans un
premier temps la période à traiter (date de début = heure H - 1, date de fin
= heure H) et une fois localisé cette portion de donnée, lit, traite et
imprime.
- sachant que l'acquisition, le calcul des bilans et la sauvegarde doivent
continuer normalement (et restés prioritaire)

Déjà je suis embetté par le simple fait que le fichier ouvert (en écriture)
par la tache d'acquisition m'empeche de l'ouvrir (en lecture) une deuxieme
fois pour la tache d'impression ? en tout cas avec la classe TFileStream de
BCB5, je vais voir du coté de la fonction C fopen ou la fonction API
OpenFile si c'est pareil...

Merci pour votre aide,

PurL
Avatar
Patrick Philippot
Vincent Burel wrote:

le flux, c'est mon job, si je te dis que c'est plus facile avec un
seul thread, c'est que c'est plus facile avec un seul thread, et tu
aura énormément de mal à démontrer que c'est plus facile avec deux
thread. D'accord ! ? :-)



Bonjour,

Je laisserai à PurL le soin de déterminer quelle est la meilleure
méthode pour son propre cas. C'est lui ou elle qui fera la démonstration
(que c'est inconfortable, ces pseudos :-) ). Et bien entendu, je
reconnais à chacun le droit d'avoir un avis différent sur les solutions
possibles. Inutile de devenir péremptoire, je reconnais votre droit à la
différence.

Ceci étant, ne mélangeons pas la manière dont le contrôleur hardware
fonctionne et la manière dont les buffers, une fois remplis, sont gérés
au niveau OS et applicatif. Il est *bien évident* que le bras du disque
ne peut pas être au même moment à 2 endroits différents et qu'il y a une
certaine atomicité au niveau des opérations de bas niveau. Cela
n'implique en aucune manière que la gestion logique des données doive
suivre le même schéma.

Nous sommes bien d'accord que les opérations de lecture et d'écriture ne
peuvent pas se chevaucher. Mais le problème ne se situe pas, à mon
humble avis, à ce niveau. Le problème est la mise en oeuvre efficace du
traitement des données respectivement lues et écrites. Si on lit ces
données, c'est pour en faire quelque chose et avant de les écrire, elles
subissent un traitement. C'est l'ensemble "traitement + opération
d'entrée/sortie" qu'il faut gérer.

Si on part sur le principe d'une boucle monothread qui lit et écrit
alternativement sans discernement ni notion de priorité, la question se
pose bien sûr de savoir à quel endroit on implémente le traitement des
données lues (ou la préparation des données écrites). Si on effectue ce
traitement dans la boucle, la prochaine écriture n'aura lieu qu'une fois
le traitement des données lues terminé (pas de choix: un seul thread -
nécessairement interrompu par d'autres threads du système). Ou
inversement, la prochaine lecture n'aura lieu qu'une fois le traitement
de préparation des données à écrire effectué et après écriture de ces
données.

Si on se contente de lire rapidement (d'alimenter un buffer avec les
données lues) et de redonner tout de suite la main à la passe suivante
pour la lecture, cela veut dire qu'il faut traiter les données lues
séparément dans une structure de type file d'attente... au moyen
(évidemment) d'un thread séparé dédié à ce traitement :-)) . Ça ne
revient pas un peu au même? Encore une fois, il me semble que la donnée
de base est que *la tâche d'écriture est prioritaire par rapport à la
tâche de lecture*. Que PurL me détrompe si ce n'est pas le cas. Dans
cette hypothèse, une implémentation en boucle suffira.

Je ne vois pas en quoi le fait d'utiliser deux threads rend la gestion
de ce mécanisme plus complexe. Au contraire. Avec une synchro
intelligente et une priorité plus grande donnée au thread le plus
critique, j'ai la garantie cette tâche prioritaire sera gérée de manière
efficace, sans être tributaire d'une tâche secondaire de moindre
importance.

Toute cette discussion me rappelle l'époque où Windows n'était pas
multithreads et où les tâches de fond étaient implémentées par le biais
de boucles de messages secondaires. Je ne dis pas que ce n'est pas
encore aujourd'hui le meilleur choix dans certains cas (une économie sur
le nombre de threads dans le système est toujours positive) mais je
n'ai pas le sentiment que cela ait rendu le design des applications plus
clair et plus efficace. Bien au contraire.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
1 2