PureBasic

Forums PureBasic
Nous sommes le Dim 26/Mai/2013 6:19

Heures au format UTC + 1 heure




Poster un nouveau sujet Répondre au sujet  [ 10 messages ] 
Auteur Message
 Sujet du message: Passer plusieurs paramètres à un thread
MessagePosté: Mar 14/Fév/2012 13:18 
Hors ligne
Avatar de l’utilisateur

Inscription: Dim 25/Mar/2007 13:44
Messages: 500
Localisation: Toulouse, France
Bonjour à vous !

Bon depuis que je code en purebasic, je suis toujours embêté avec ces fichus threads. A chaque fois qu'on veut passer plusieurs paramètres à un thread, il faut bidouiller une structure et faire hyper attention à ce qu'on fait.

En général, lorsqu'on veut passer plusieurs paramètres à un thread, on conçoit une structure (rien que pour ça bien souvent), et on met dans cette structure tout ce qu'on veut envoyer à notre thread. Alors c'est plutôt une bonne technique sauf que:
1° On est obligé de concevoir une structure rien que pour cela
2° Si on veut rajouter un paramètre, il faut changer la structure
3° On se retrouve souvent avec des "Invalid Memory Access"

Je vais insister sur ce dernier point: l'une des raisons qui fait qu'on a des erreurs d'accès mémoire c'est qu'on passe la structure à notre thread par pointeur. De ce fait, il faut que ce pointeur et toutes les données qu'il contient restent valides durant toute la vie du thread. Et parfois, on oublie ou on copie mal certaines données qui font que ben .. ca plante sans qu'on comprenne pourquoi.
Je donne un exemple:
Code:
Structure test
  param1.i
  param2.s
EndStructure

;structure du thread
Structure th
  var1.i
  var2.s
  var.test
EndStructure


Procedure thread(*paramList.th)
  Delay(2000) ;attente de la fin de la fonction appelante
 
  Debug *paramList\var1
  Debug *paramList\var2
  Debug *paramList\var\param1
  Debug *paramList\var\param2
EndProcedure

Procedure callThread()
  var1.i = 1234
  var2.s = "test"
  var.test\param1 = 789
  var\param2 = "Hello World !"
 
  envoi.th
  envoi\var1 = var1
  envoi\var2 = var2
  envoi\var = var
 
  t = CreateThread(@thread(), @envoi)
  ProcedureReturn t
EndProcedure

WaitThread(callThread())

Théoriquement, vous devriez voir des variables erronées s'afficher (si ce n'est un plantage). Dans ce code, tout le problème est que j'appelle le thread via une procédure. Or à la fin de la procédure, toutes les variables créées par celle-ci sont tout simplement supprimées (elles sont locales à la procédure). Du coup, notre thread se retrouve avec un pointeur sur une zone mémoire qui n'est plus allouée.

Pour palier à ce problème j'ai donc fait quelques fonctions qui permettent de nous simplifier la vie. Ces procédures permettent d'ajouter simplement des paramètres à une unique ressource. C'est ensuite cette ressources qui est passée au thread et d'autres procédures permettent de récupérer les différents paramètres de la ressource:
Code:
; **************************************************
; Gestionnaire de passage de parametres à un Thread.
; Par SERIN Kévin
; PB 4.51
; **************************************************

;Structure contenant la liste des adresses des parametres.
Structure PThread
  List param.i()
EndStructure

;Instancie une liste de paramètres.
;   return: une ressource de type PThread.
Procedure pThread_create()
  *pThread.PThread = AllocateMemory(SizeOf(PThread))
  NewList *pThread\param()
 
  ProcedureReturn *pThread
EndProcedure

;Fait une copie de la donnée et l'ajoute à la liste des paramètres.
;Attention: pour les structures, utilisez la macro pThread_addStruct().
;   pThread:  ressource PThread (créée avec pThread_create() )
;   value:    adresse de la donnée à ajouter
;   size:     taille de la donnée à ajouter
Procedure pThread_addValue(*pThread.PThread, *value, size.i)
  *newElement = AllocateMemory(size)
  CopyMemory(*value, *newElement, size)
 
  AddElement(*pThread\param())
  *pThread\param() = *newElement
EndProcedure

;Ajoute directement une adresse à la liste des paramètres.
;Attention: aucune copie n'est effectuée, la zone mémoire doit donc restée accessible à tout moment. Préférez pThread_addValue().
;   pThread:  ressource PThread (créée avec pThread_create() ).
;   adrs:     adresse à ajouter.
Procedure pThread_addAddress(*pThread.PThread, *adrs)
  AddElement(*pThread\param())
  *pThread\param() = *adrs
EndProcedure

;Récupère l'adresse du ième paramètre (commence à 1).
;   pThread:  ressource PThread (créée avec pThread_create() ).
;   i:        index du paramètre.
Procedure pThread_get(*pThread.PThread, i.i)
  SelectElement(*pThread\param(), i-1)
  ProcedureReturn *pThread\param()
EndProcedure

;Libère une ressource PThread ainsi que tous les paramètres
;   pThread:  ressource PThread (créée avec pThread_create() ).
Procedure pThread_free(*pThread.PThread)
  ForEach *pThread\param()
    FreeMemory(*pThread\param())
  Next
  ClearList(*pThread\param())
  FreeMemory(*pThread)
EndProcedure

;Macro permettant d'ajouter une structure à la liste des paramètres.
;   pThread:  ressource PThread (créée avec pThread_create() ).
;   varAdrs:  adresse de la variable contenant la structure à ajouter.
;   tempVar:  nom de variable temporaire (poubelle). Ce nom ne doit pas être utilisé par une autre variable de votre code.
;   struct:   nom de la structure de la variable.
Macro pThread_addStruct(pThread, varAdrs, tempVar, struct)
  tempVar = AllocateMemory(SizeOf(struct))
  CopyStructure(varAdrs, tempVar, struct)
  pThread_addAddress(pThread, tempVar)
EndMacro


Et voilà ce que ca donne avec l'exemple de tout à l'heure:
Code:
; ********
; Exemple:
; ********

Structure test
  param1.i
  param2.s
EndStructure

Procedure thread(paramList)
  Delay(2000) ;attente de la fin de la fonction appelante
 
  var1.i = PeekI(pThread_get(paramList, 1)) ;récupération du 1er parametre
  var2.s = PeekS(pThread_get(paramList, 2)) ;récupération du 2e parametre
  *varStruct.test = pThread_get(paramList, 3) ;récupération du 3e parametre
 
  Debug var1
  Debug var2
  Debug *varStruct\param1
  Debug *varStruct\param2
 
  pThread_free(paramList) ;liberation des ressources à la fin du thread
EndProcedure

Procedure callThread()
  var1.i = 1234
  var2.s = "test"
  var.test\param1 = 789
  var\param2 = "Hello World !"
 
  param = pThread_create()
  pThread_addValue(param, @var1, SizeOf(Integer))
  pThread_addValue(param, @var2, Len(var2)+1)
  pThread_addStruct(param, @var, tmp, test)
  t = CreateThread(@thread(), param)
  ProcedureReturn t
EndProcedure

WaitThread(callThread())

Là tout se passe bien, aucune erreur. =)

Voilà en espérant que cela vous serve à quelque chose.


Haut
 Profil  
 
 Sujet du message: Re: Passer plusieurs paramètres à un thread
MessagePosté: Mar 14/Fév/2012 14:03 
Hors ligne

Inscription: Mer 11/Nov/2009 18:17
Messages: 1251
Localisation: Poitiers (Vienne)
C'est vrais que c'est énèrvent sa !

Pour moi c'est du chinoi :wink:

_________________
La vie, C'est comme, Une boitte, De startis, On en voie, De toutes, Les couleurs !

Mon forum http://purebasic.forumphp3.com/index.php


Haut
 Profil  
 
 Sujet du message: Re: Passer plusieurs paramètres à un thread
MessagePosté: Mar 14/Fév/2012 14:31 
Hors ligne

Inscription: Mer 14/Sep/2011 16:59
Messages: 335
Une autre façon est de définir des variables globales qui ont donc une durée de vie indépendante des threads.

Chez moi ça marche (avec option du compilateur à "activer la gestion des threads" même si bizarrement ça marche sans ?!))

J'ai juste ajouté 2 variables globales en lignes 13 et 14.
Code:
Structure test
  param1.i
  param2.s
EndStructure

;structure du thread
Structure th
  var1.i
  var2.s
  var.test
EndStructure

Global var.test
Global envoi.th

Procedure thread(*paramList.th)
  Delay(2000) ;attente de la fin de la fonction appelante

  Debug *paramList\var1
  Debug *paramList\var2
  Debug *paramList\var\param1
  Debug *paramList\var\param2
EndProcedure

Procedure callThread()
  var1.i = 1234
  var2.s = "test"
  var.test\param1 = 789
  var\param2 = "Hello World !"

  ;envoi.th
  envoi\var1 = var1
  envoi\var2 = var2
  envoi\var = var

  t = CreateThread(@thread(), @envoi)
  ProcedureReturn t
EndProcedure

WaitThread(callThread())


Mesa.


Haut
 Profil  
 
 Sujet du message: Re: Passer plusieurs paramètres à un thread
MessagePosté: Mar 14/Fév/2012 14:38 
Hors ligne
Avatar de l’utilisateur

Inscription: Dim 25/Mar/2007 13:44
Messages: 500
Localisation: Toulouse, France
Eh bien je vais peut-être passer pour un puriste mais je suis complètement anti-globales ^^ On les oublie souvent et on peut parfois les écraser sans s'en rendre compte (surtout sur les gros projets).
De plus, avec cette méthode on ne peut pas appeler plusieurs thread de la même procédure avec des paramètres différents(et je trouve ca un peu bête quand même ^^ ).


Haut
 Profil  
 
 Sujet du message: Re: Passer plusieurs paramètres à un thread
MessagePosté: Mar 14/Fév/2012 15:56 
Hors ligne

Inscription: Mer 14/Sep/2011 16:59
Messages: 335
Pour ma part, être anti-global est nécessaire dans le contexte de l'encapsulation de la programmation orientée objet (poo) sinon je trouve plus facile de créer un pbi nommé "global" dont toutes les variables globales commence par... "GLOBALE_". Et là il est impossible d'oublier ou de confondre quoique ce soit.

ça revient au même mais ça évite de créer des variables temporaires et de faire des échanges permanents entre elles.

Mais bon, chacun fait comme il lui plaît...

Existent-t-ils de gros projets sans poo ? en Purebasic ?
Je ne sais pas, peut-être.

J'ai essayé de faire ça avec ton code
Citation:
De plus, avec cette méthode on ne peut pas appeler plusieurs thread de la même procédure avec des paramètres différents(et je trouve ca un peu bête quand même ^^ ).

et je n'y suis pas arrivé. Peux-tu me montrer stp ? ça m'intéresse.

Mesa.


Haut
 Profil  
 
 Sujet du message: Re: Passer plusieurs paramètres à un thread
MessagePosté: Mar 14/Fév/2012 16:03 
Hors ligne
Avatar de l’utilisateur

Inscription: Dim 25/Mar/2007 13:44
Messages: 500
Localisation: Toulouse, France
Code:
IncludeFile "pThread.pbi"

; ********
; Exemple:
; ********

Structure test
  param1.i
  param2.s
EndStructure

Procedure thread(paramList)
  Delay(2000) ;attente de la fin de la fonction appelante
 
  var1.i = PeekI(pThread_get(paramList, 1))
  var2.s = PeekS(pThread_get(paramList, 2))
  *varStruct.test = pThread_get(paramList, 3)
 
  Debug var1
  Debug var2
  Debug *varStruct\param1
  Debug *varStruct\param2
 
  pThread_free(paramList) ;liberation des ressources à la fin du thread
EndProcedure

Procedure callThread()
  var1.i = 1234
  var2.s = "test"
  var.test\param1 = 789
  var\param2 = "Hello World !"
 
  param = pThread_create()
  pThread_addValue(param, @var1, SizeOf(Integer))
  pThread_addValue(param, @var2, Len(var2)+1)
  pThread_addStruct(param, @var, tmp, test)
 
 
  ;2e thread
  var1.i = 50
  var2.s = "test deux le retour"
  var.test\param1 = 12
  var\param2 = "Hello World ! (deux)"
  param2 = pThread_create()
  pThread_addValue(param2, @var1, SizeOf(Integer))
  pThread_addValue(param2, @var2, Len(var2)+1)
  pThread_addStruct(param2, @var, tmp, test)
 
  ;envoi des 2 threads en meme temps
  t = CreateThread(@thread(), param)
  t = CreateThread(@thread(), param2)
  ProcedureReturn t
EndProcedure

callThread()
Delay(5000) ;attente des threads


Bon j'ai mis les appels des 2 threads dans la même fonction mais c'est pour montrer le principe. C'est plus clair comme ca ?


Haut
 Profil  
 
 Sujet du message: Re: Passer plusieurs paramètres à un thread
MessagePosté: Mar 14/Fév/2012 18:41 
Hors ligne

Inscription: Mer 14/Sep/2011 16:59
Messages: 335
Excellent, merci.


Haut
 Profil  
 
 Sujet du message: Re: Passer plusieurs paramètres à un thread
MessagePosté: Mer 15/Fév/2012 13:15 
Hors ligne
Avatar de l’utilisateur

Inscription: Dim 25/Mar/2007 13:44
Messages: 500
Localisation: Toulouse, France
Avec plaisir =)
En espérant que ca soit utile à d'autres =)


Haut
 Profil  
 
 Sujet du message: Re: Passer plusieurs paramètres à un thread
MessagePosté: Dim 19/Fév/2012 16:49 
Hors ligne
Avatar de l’utilisateur

Inscription: Sam 21/Mai/2005 17:50
Messages: 895
C'est vraiment sympa ce que tu as fait, simplement dans le cas d'une manipulation de donnée qui doit être rapide, il me semble que ça alourdi un peu les choses.

de mon coté Je vois les threads comme une famille de procédure, donc créer une structure associée à chaque thread n'est pas un soucis, il me semble, de cette manière comme on peut maintenant mettre tout les objets PB dans une structure (liste, array, map), on peut avoir accès aux données transmises simplement et de manière pratique avec l'autocomplétion (pendant le codage)

ensuite c'est vrai que lors du lancement d'un thread par procédure il faut absolument faire attention à ce que les données aient une durée de vie plus grande que celle du thread.

Du coup pour ne pas avoir ce problème, utiliser une var globale avec en structure toutes les données du prog me semble être plus "pratique" dans ce que ça t'oblige à maitriser les données que tu stockes.

_________________
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))


Haut
 Profil  
 
 Sujet du message: Re: Passer plusieurs paramètres à un thread
MessagePosté: Dim 19/Fév/2012 20:00 
Hors ligne
Avatar de l’utilisateur

Inscription: Dim 25/Mar/2007 13:44
Messages: 500
Localisation: Toulouse, France
graph100 a écrit:
C'est vraiment sympa ce que tu as fait, simplement dans le cas d'une manipulation de donnée qui doit être rapide, il me semble que ça alourdi un peu les choses.


Certes, il n'y a pas de doute là-dessus. Mais selon moi, ce qui doit être "rapide" c'est l’exécution du thread en lui même et pas tellement son initialisation. Je pense qu'il vaut mieux optimiser ses algorithmes plutôt que de supprimer ces 2-3 accès mémoire en plus ;).
D'autant plus que le soucis avec les threads c'est bien souvent qu'on a l'impression que ca marche (parce qu'on a de la chance) et un bon jour pouf, le programme plante sans vraiment qu'on comprenne pourquoi.

Enfin après chacun doit s'adapter à la situation mais je pense que dans la majeure partie des cas, c'est rassurant d'avoir un thread avec un zone mémoire bien définie et personnelle afin d'avoir un programme stable.


Haut
 Profil  
 
Afficher les messages postés depuis:  Trier par  
Poster un nouveau sujet Répondre au sujet  [ 10 messages ] 

Heures au format UTC + 1 heure


Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 1 invité


Vous ne pouvez pas poster de nouveaux sujets
Vous ne pouvez pas répondre aux sujets
Vous ne pouvez pas éditer vos messages
Vous ne pouvez pas supprimer vos messages

Rechercher:
Aller à:  

 


Powered by phpBB © 2008 phpBB Group | Traduction par: phpBB-fr.com
subSilver+ theme by Canver Software, sponsor Sanal Modifiye