Multithreading et pile fifo [Résolu]

Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention - 28 juil. 2010 à 17:52 - Dernière réponse : Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention
- 30 juil. 2010 à 09:46
Bonjour ,

J'améliore en ce moment une classe journal. J'ai remarqué que quand beaucoup de problème survienne l'écriture de mon fichier journal ralentie l'exécution de mes programmes (et de beaucoup quand même ).

Pour corrigé ce problème j'ai pensé au multithreading avec une pile fifo (et j'ai fini par m'en tiré tout seul comme une grand ).En résumé j'ajoute mes messages à ma pile dans le thread principale et je les extrais dans un tread supplémentaire dédié à l'écriture de ce fichier (en utilisant des délégués si non sa ne fonctionnerais pas ).

Problème, je ne peut pas lire ma pile en même temps que l'écriture (si non je ne retrouve plus mes textes, ce qui peut s'expliquer ce n'est pas la question , d'ailleurs ce message me fait pensé que je ne doit pas pouvoir lire la ligne que je suis entrain d'écrire mais que les autres si, même si a mon havie sa devrais être la classe pile, "Queue", qui devrais gérer ce problème et pas moi, merci d'avoir pensé a ce problème M.Microbof ).

Donc pour éviter sa (lecture en même temps que l'écriture) j'ai ajouté une variable qui passe à vrais au moment où j'exécute "Enqueue" sur ma pile puis tout de suite à faux soit :
EcritureDansLaPileEnCour = True
PileAEcrire.Enqueue(MaLigne)
EcritureDansLaPileEnCour =  False


Et dans la fonction de lecture de la pile :
While EcritureDansLaPileEnCour
   Threading.Thread.CurrentThread.Sleep(10)
End While
Return PileAEcrire.Dequeue


Donc si je suis en cour écriture dans la pile la lecture ne se fait pas (enfin je pense ).

Sa fonctionne bien mais il doit forcément exister quelque chose de plus propre que Sleep ?

Ma question est donc :
Comment faire l'équivalent (ou mieux que sa ) plus proprement ?

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
Afficher la suite 

7 réponses

Répondre au sujet
foliv57 423 Messages postés vendredi 17 novembre 2006Date d'inscription 15 juillet 2014 Dernière intervention - 29 juil. 2010 à 14:18
+3
Utile
Oui, dans l'exemple que je vous ai donné, je n'ai pas assé bien expliqué que ce sont deux méthodes différentes. On utilisera donc soit les SyncLock, soit la synchronizedQueue. Utiliser les deux ensemble est inutil.

Si vous utilisez la synchronizedQueue, vous n'avez plus besoin de gérer quoi que ce soit. Vous pouvez utiliser l'objet normalement, peut importe le thread, c'est elle qui va gérer en interne les verroux.


Maintenant pour la méthode avec SyncLock je vais vous expliquer les points que vous avez constaté.

Je doit "locké" ma pile en lecture ET en écriture


Oui, car si on regarde bien, que ce soit Enqueue ou Dequeue, l'objet est toujours modifié, donc c'est plus ou moins toujours une écriture de l'objet. D'autant plus qu'il ne faudrait pas compter le nombre d'objets dans la queue alors qu'un autre thread est en train d'en ajouter.

Le "End SyncLock" est sans doute exécutée implicitement à la fin de la procédure.


C'est justement l'avantage de cette syntaxe, le "End SyncLock" est exécuté quoi qu'il arrive (Exception ou fin de méthode dans le syncLock). Ce qui permet de ne jamais se retrouver avec un objet locké en permanence. (Petite note au passge : Ce comportement est aussi applicable au mot clé USING qui garantie l'éxécution du End Using. Très pratique lorsqu'on utilise des connections à BDD par exemple)

Déjà je n'avais pas ajouté le ".SyncRoot" comme foliv57 me le montrais dans son exemple (mais sa ne semble pas changé grand chose dans mon cas ).


J'avoue que je suis resté vague sur le sujet. Donc voici l'expliquation.
L'instruction SyncLock peut vérouiller nimporte quel objet de type référence (Classe, Etc ....). Ensuite si un autre thread tante de faire à sont tour un SyncLock sur le même objet, il sera bloqué tant que celui-ci ne sera pas déverrouillé (End SyncLoock). Donc oui, on peut très bien verrouiller tout l'objet Queue.

MAIS : Le verrouillage de l'objet necessite des resources et, je vous le donne en mille, plus l'objet est complex, plus le verrouillage necessite de ressources.

Il est donc judicieux de verrouiller l'objet le plus simple possible (tout bêtement "dim monVerroux as new Object()" par exemple). Ceci explique pourquoi la Class Queue met à disposition un objet .SyncRoot pouvant être verrouillé.

Grossièrement notre SyncRoot est notre barrière qui nous permet de bloquer l'accès à notre objet.
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de foliv57
Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention - 30 juil. 2010 à 09:46
+3
Utile
Ok, merci beaucoup pour toutes ces précisions

Bà je pense avoir tout compris grâce à ces explications supplémentaire, j'ai plus de question sur le sujet

Personnellement je fait le choix d'utilisé les SyncLock plutôt que les "Queue.Synchronized" car j'aime avoir la main sur ce qui se passe.

Donc si quelqu'un cherche à faire la même chose (la majeur partie des info m'ont été fournis par foliv57, c'est lui qui faut remercier, je conseil VIVEMENT de lire son poste précédant qui est très claire ) :

Déclaration de la pile (rien de particulier) :
Dim/Private/Public MaPile As (New) Queue


Écriture dans la pile :
'L'instruction SyncLock verrouille un objet ou attend que l'objet soit déverrouillé
SyncLock (MaPile.SyncRoot)
   MaPile.Enqueue(ObjAAjouterDansLaPile)
End SyncLock


Lecture dans la pile :
'L'instruction SyncLock verrouille un objet ou attend que l'objet soit déverrouillé
'On peut remplacer "ValeurLutDansLaPile =" par "Return" dans ce cas le "End SyncLock" sera exécuté implicitement 
SyncLock (MaPile.SyncRoot)
   ObjLutDansLaPile = MaPile.Dequeue
End SyncLock


Pour tout accès à la pile il faut le verrouiller avec SyncLock si non un comportement étrange est à craindre (même pour un ".count")

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Polack77
Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention - 29 juil. 2010 à 10:16
0
Utile
Déjà merci pour cette réponse

Donc si j'ai bien compris (je suis dans une classe, même si je pense que sa ne change pas grand chose ) :

Déclaration de mes variables :
Avec mes noms de variables :
Private PileAEcrire As New Queue
Private SynchronizedPileAEcrire As Queue =   Queue.Synchronized(PileAEcrire)

Soit dans votre exemple :
Dim myQueue As New Queue()
Dim mySynchronizedQueue As Queue  = Queue.Synchronized(myQueue)


Fonction de remplissage de ma pile :
Avec mes noms de variables :
Public Sub AddLigne (...)
   [...]
   SyncLock (PileAEcrire)
      PileAEcrire.Enqueue(MaLigne)
   End SyncLock
   [...]
End Sub

Soit dans votre exemple :
SyncLock (myQueue.SyncRoot)
    myQueue.Enqueue(New Object())
End SyncLock


Fonction de lecture de ma pile (appelé par déléguer) :
Avec mes noms de variables :
Private Function GetLigneEcrire() As String
   Return SynchronizedPileAEcrire.Dequeue
End Function

Soit dans votre exemple :
   mySynchronizedQueue.Dequeue


(A moins que je doive remplir et vidé ma pile à partir du même objet, ou testé la valeur IsSynchronized ??? Et dans ce cas là quel objet faut-il testé ?)

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
Commenter la réponse de Polack77
Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention - 29 juil. 2010 à 10:43
0
Utile
Arf j'ai pas mal de soucis en final avec cette façon de faire :

Il semble que ma pile soit limité à 512 éléments (normal ), comment faire pour augmenté cette capacité (de mémoire je pouvais en mettre plus de 5000 avec mon ancienne façon de faire) ?

Certain message sont perdu durant la lecture (sans doute à cause de mon remplissage par la pile et non par le pile Synchronized, je fait encore des tests )

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
Commenter la réponse de Polack77
Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention - 29 juil. 2010 à 10:56
0
Utile
Ok je pense que j'ai compris mon erreur :
Je doit "locké" ma pile en lecture ET en écriture (je test en lisant et en écrivant avec la pile synchroniser et je ne rencontre plus de bug )
Soit :
Déclaration :
Private PileAEcrire As New Queue
Private SynchronizedPileAEcrire As Queue =  Queue.Synchronized(PileAEcrire)


Écriture :
SyncLock (SynchronizedPileAEcrire)
   SynchronizedPileAEcrire.Enqueue(CreeLigneJournal(e.Row))
End SyncLock


Lecture :
SyncLock (SynchronizedPileAEcrire)
   Return SynchronizedPileAEcrire.Dequeue
End SyncLock


Tiens en tapant ce message je me dit que dans la lecture vue que je fait un Return de la valeur de ma pile la ligne "End SyncLock" n'est jamais exécuter, pourtant j'arrive toujours à insérer des données dans me pile. Le "End SyncLock" est sans doute exécutée implicitement à la fin de la procédure.

Si je me trompe corrigé moi svp

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
Commenter la réponse de Polack77
Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention - 29 juil. 2010 à 11:23
0
Utile
Bon bà vous aurez tout l'historique de mes tests je pense

J'ai remarqué quelque truc :
Déjà je n'avais pas ajouté le ".SyncRoot" comme foliv57 me le montrais dans son exemple (mais sa ne semble pas changé grand chose dans mon cas ).
MSDN "Queue.SyncRoot"
Semble me dire que oui il faut que j'utilise cette propriété mais :
MSDN "SyncLock"
Semble me dire que SyncLock verrouille l'objet reçu

A moins que j'ai raté un épisode

Donc que fait le ".SyncRoot" en final

De plus j'ai testé de faire la même chose que précédemment mais sans utilisé le "SynchronizedQueue" (soit travailler directement ma pile et non la pile synchronisé, locker ma pile au moment de l'écriture et de la lecture) et le comportement est exactement le même

Donc pourquoi faire une pile synchronisé

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
Commenter la réponse de Polack77
foliv57 423 Messages postés vendredi 17 novembre 2006Date d'inscription 15 juillet 2014 Dernière intervention - 28 juil. 2010 à 21:11
-2
Utile
Bonjour,

Il est clair que l'objet Queue n'étant pas threadsafe (qu'on pourrait traduire par 'Protégé contre les accès simultanés'), il faut de ce fait synchronizer les opérations.

Pour ce faire, deux méthodes :

1) L'objet Queue met a disposition une propriété SyncRoot qui vous permet de synchroniser vos accès :
Dim myQueue As New Queue()

SyncLock (myQueue.SyncRoot)
    myQueue.Enqueue(New Object())
End SyncLock

Toutes les actions sur la queue contenues entre SyncLock et End SyncLock ne sont accessible qu'à un seul thread à la fois. L'instruction SynckLock garantie aussi la libération de l'objet en cas d'exception non gérée (et ca c'est plutot simpa).

2) Créer une Queue synchronisée de cette manière:
Dim myQueue As New Queue()
Dim mySynchronizedQueue As Queue = Queue.Synchronized(myQueue)

Ensuite vous pouvez utiliser mySynchronizedQueue sans vous soucier de l'accès simultané.
Commenter la réponse de foliv57

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.