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

Objets et Threads

5 réponses
Avatar
Alex
Bonjour, j'expérimente l'utilisation des threads.
Je souhaite les gérer via une classe.

J'arrive à lancer les threads qui font les calculs en //.
Mon souci c'est pour les arrêter.

J'ai un bouton dans la fenêtre (thread principal) qui appelle la methode
oT:mbFin() pour le stopper.
L'attribut :abFin de l'objet est mis à vrai.
Dans le traitement en boucle (thread secondaire),
je lis l'attribut :abFin (oT:mbBoucle()) et je suis sencé sortir de la
boucle. ce qui devrait terminer le thread.

Hors quand je mets :abFin à vrai dans le thread principal,
il est toujours à Faux dans le thread secondaire !!!

D'ou ma question :
comment faire pour partager un objet de classe entre deux threads?

Merci pour vos lumières,

Alex


// Lancement Nouveau thread via un Bouton dans la fenetre principale
cThread::gbNouveau("FEN_Treads.plCalcul")

// ********** Procedure Stop locale à une fenêtre ******************

PROCEDURE plStop()

nInd est un entier
oT est un cThread dynamique
nInd = TableSelect(TABLE_Treads)

SI PAS nInd>0 ALORS
RETOUR
FIN

// Stop thread
oT=cThread::gtListe[COL_Nom[nInd]]
SI oT<>Null ALORS
oT:mbFin()
FIN

// ********** Procedure Calcul locale à une fenêtre ******************

PROCEDURE plCalcul(oT est un cThread dynamique)

// Entrée thread

// Traitement en boucle
TANTQUE oT:mbBoucle()
// Calculs ...
FIN

// Sortie thread

CAS EXCEPTION:
RETOUR

// ************************ Init nouveau Thread ******************

PROCEDURE mbInitialise()

:asNom = "oThread_"+DonneIdentifiant()
::gtListe[:asNom] = objet

RENVOYER Vrai

// *********** Methode Lancement nouveau Thread ******************

PROCEDURE GLOBALE gbNouveau(LOCAL sProcedure est une chaîne)

// Mode
ThreadMode(threadSectionCritique)

oT est un cThread
oT:mbInitialise()

// On exécute le thread
ThreadExécute(oT:asNom, threadNormal, sProcedure, oT)

// On attend que le thread se soit lancé
ThreadAttendSignal()

RENVOYER Vrai

// ************************* Classe Thread **********************

cThread est une classe

PUBLIQUE CONSTANT

asNom est une chaîne // oThread_13

// Arret
abFin est un booléen
abBoucle est un booléen

GLOBAL CONSTANT

// Tous les threads
gtListe est un tableau associatif de cThread

FIN

// ************************* Methode Boucle *********************

PROCEDURE mbBoucle()

// Début thread :
// on envoie le signal de début au programme
:mbSignal()

// Demande de fin -> Exit
SI :abFin ALORS
RENVOYER Faux
FIN

RENVOYER Vrai

// ************************* Methode Signal *********************

PROCEDURE PRIVÉE mbSignal()

// On indique que le thread est lancé
SI PAS :abBoucle ALORS
ThreadEnvoieSignal(".")
:abFin = Faux
:abBoucle = Vrai
FIN

RENVOYER :abBoucle

// ************ Methode Pour arreter un thread *******************

PROCEDURE mbFin(LOCAL bForce est un booléen=Faux)

// En principe ceci est censé arrêter le thread
:abFin = Vrai

// On arrête tous les threads existants
SI bForce ALORS
// On regarde si le thread existe
SI :mbExiste() ALORS
// Tentative d'arrêt du thread
SI PAS :mbArrete() ALORS
// On vérifie qu'il existe toujours
SI :mbExiste() ALORS
Erreur("Impossible d'arreter le thread <"+:asNom+">")
FIN
FIN
FIN
FIN

RENVOYER Vrai

5 réponses

Avatar
free
Bonjour

Ton raisonnement est bon, t'as juste un bug dans ton code:
tu appelle le mbFin() de oT, qui est une COPIE

Comme si tu avais :
tabFLAGARRET est un tableau de x BOOLEEN
b est un boolean
b=tabFLAGARRET[i]
b=VRAI

b vaut VRAI mais tabFLAGARRET[i] vaut toujours faux

"Alex" wrote in message
news:4be110a5$0$29925$
Bonjour, j'expérimente l'utilisation des threads.
Je souhaite les gérer via une classe.

J'arrive à lancer les threads qui font les calculs en //.
Mon souci c'est pour les arrêter.

J'ai un bouton dans la fenêtre (thread principal) qui appelle la methode
oT:mbFin() pour le stopper.
L'attribut :abFin de l'objet est mis à vrai.
Dans le traitement en boucle (thread secondaire),
je lis l'attribut :abFin (oT:mbBoucle()) et je suis sencé sortir de la
boucle. ce qui devrait terminer le thread.

Hors quand je mets :abFin à vrai dans le thread principal,
il est toujours à Faux dans le thread secondaire !!!

D'ou ma question :
comment faire pour partager un objet de classe entre deux threads?

Merci pour vos lumières,

Alex


// Lancement Nouveau thread via un Bouton dans la fenetre principale
cThread::gbNouveau("FEN_Treads.plCalcul")

// ********** Procedure Stop locale à une fenêtre ******************

PROCEDURE plStop()

nInd est un entier
oT est un cThread dynamique
nInd = TableSelect(TABLE_Treads)

SI PAS nInd>0 ALORS
RETOUR
FIN

// Stop thread
oT=cThread::gtListe[COL_Nom[nInd]]
SI oT<>Null ALORS
oT:mbFin()
FIN

// ********** Procedure Calcul locale à une fenêtre ******************

PROCEDURE plCalcul(oT est un cThread dynamique)

// Entrée thread

// Traitement en boucle
TANTQUE oT:mbBoucle() // Calculs ...
FIN

// Sortie thread

CAS EXCEPTION:
RETOUR

// ************************ Init nouveau Thread ******************

PROCEDURE mbInitialise()

:asNom = "oThread_"+DonneIdentifiant()
::gtListe[:asNom] = objet

RENVOYER Vrai

// *********** Methode Lancement nouveau Thread ******************

PROCEDURE GLOBALE gbNouveau(LOCAL sProcedure est une chaîne)

// Mode
ThreadMode(threadSectionCritique)

oT est un cThread
oT:mbInitialise()

// On exécute le thread
ThreadExécute(oT:asNom, threadNormal, sProcedure, oT)

// On attend que le thread se soit lancé
ThreadAttendSignal()

RENVOYER Vrai

// ************************* Classe Thread **********************

cThread est une classe

PUBLIQUE CONSTANT

asNom est une chaîne // oThread_13

// Arret
abFin est un booléen
abBoucle est un booléen

GLOBAL CONSTANT

// Tous les threads
gtListe est un tableau associatif de cThread

FIN

// ************************* Methode Boucle *********************

PROCEDURE mbBoucle()

// Début thread :
// on envoie le signal de début au programme
:mbSignal()

// Demande de fin -> Exit
SI :abFin ALORS
RENVOYER Faux
FIN

RENVOYER Vrai

// ************************* Methode Signal *********************

PROCEDURE PRIVÉE mbSignal()

// On indique que le thread est lancé
SI PAS :abBoucle ALORS
ThreadEnvoieSignal(".")
:abFin = Faux
:abBoucle = Vrai
FIN

RENVOYER :abBoucle

// ************ Methode Pour arreter un thread *******************

PROCEDURE mbFin(LOCAL bForce est un booléenúux)

// En principe ceci est censé arrêter le thread
:abFin = Vrai

// On arrête tous les threads existants
SI bForce ALORS
// On regarde si le thread existe
SI :mbExiste() ALORS // Tentative d'arrêt du thread
SI PAS :mbArrete() ALORS
// On vérifie qu'il existe toujours
SI :mbExiste() ALORS
Erreur("Impossible d'arreter le thread <"+:asNom+">")
FIN
FIN
FIN
FIN

RENVOYER Vrai
Avatar
Alex
Je suppose que le bug dont tu parles se situe ici :

oT est un cThread dynamique
...
oT=cThread::gtListe[COL_Nom[nInd]]
oT:mbFin()

// BUG ??? -> ICI ON FAIT UNE COPIE DE LOBJET ???
// IL ME SEMBLE QUE NON VU QUE oT est Dynamique
// UNE AFFECTATION SUR UN OBJET DYNAMIQUE = RÉFÉRENCE

D'autre part si j'ajoute une trace apres oT:mbFin(), l'attribut :abFin
des deux objets est à Vrai.
Ceci me fait penser que j'ai bien une référence sur l'objet et non une
copie (cf. code ci-après).

A priori le fait d'utiliser un thread fait que les valeurs affectées
dans le thread principal ne sont pas a jour dans le thread
secondaire.
Extrait de l'aide : http://doc.pcsoft.fr/fr-FR/?3077004
Ecritures et affectations dans un thread : Si des écritures ou des
affectations sont effectuées dans un thread,
les autres threads en cours d'exécution ne partagent pas ces
informations. Certaines incohérences peuvent apparaître.

Donc le problème reste entier.
Comment faire pour partager un objet entre deux threads?

// ********** Procedure Stop locale à une fenêtre ******************

PROCEDURE plStop()

nInd est un entier
oT est un cThread dynamique
nInd = TableSelect(TABLE_Treads)

SI PAS nInd>0 ALORS
RETOUR
FIN

// Stop thread
oT=cThread::gtListe[COL_Nom[nInd]]
SI oT<>Null ALORS
oT:mbFin()
FIN

// Ici les deux objets (celui du tableau cThread et celui déclaré
localement oT) ont l'attribut :abFin à Vrai
// Il semble donc que oT est bien une référence à
cThread::gtListe[COL_Nom[nInd]]
// L'appel oT:mbFin() a bien affecté les deux objets.
Trace(...
"Objet original du tableau : <"+cThread::gtListe[COL_Nom[nInd]]:abFin
+">"+RC+...
"Objet dynamique local : <"+oT:abFin+">")

STOP
Avatar
Albert P.
"Alex" a écrit dans le message de news:

Je suppose que le bug dont tu parles se situe ici :

oT est un cThread dynamique
...
oT=cThread::gtListe[COL_Nom[nInd]]
oT:mbFin()

// BUG ??? -> ICI ON FAIT UNE COPIE DE LOBJET ???
// IL ME SEMBLE QUE NON VU QUE oT est Dynamique
// UNE AFFECTATION SUR UN OBJET DYNAMIQUE = RÉFÉRENCE

D'autre part si j'ajoute une trace apres oT:mbFin(), l'attribut :abFin
des deux objets est à Vrai.
Ceci me fait penser que j'ai bien une référence sur l'objet et non une
copie (cf. code ci-après).

A priori le fait d'utiliser un thread fait que les valeurs affectées
dans le thread principal ne sont pas a jour dans le thread
secondaire.
Extrait de l'aide : http://doc.pcsoft.fr/fr-FR/?3077004
Ecritures et affectations dans un thread : Si des écritures ou des
affectations sont effectuées dans un thread,
les autres threads en cours d'exécution ne partagent pas ces
informations. Certaines incohérences peuvent apparaître.

Donc le problème reste entier.
Comment faire pour partager un objet entre deux threads?

// ********** Procedure Stop locale à une fenêtre ******************

PROCEDURE plStop()

nInd est un entier
oT est un cThread dynamique
nInd = TableSelect(TABLE_Treads)

SI PAS nInd>0 ALORS
RETOUR
FIN

// Stop thread
oT=cThread::gtListe[COL_Nom[nInd]]
SI oT<>Null ALORS
oT:mbFin()
FIN

// Ici les deux objets (celui du tableau cThread et celui déclaré
localement oT) ont l'attribut :abFin à Vrai
// Il semble donc que oT est bien une référence à
cThread::gtListe[COL_Nom[nInd]]
// L'appel oT:mbFin() a bien affecté les deux objets.
Trace(...
"Objet original du tableau : <"+cThread::gtListe[COL_Nom[nInd]]:abFin
+">"+RC+...
"Objet dynamique local : <"+oT:abFin+">")

STOP



Bonjour,

Si mes souvenirs de classe (lointains) sont bon, il faudrait regarder dans
la doc du coté des sémaphores ...

Albert P.
Avatar
Alex
Bon problème résolu :

J'appelle ThreadExécute et lui passe en paramètre :
-le nom de la procedure à lancer
-mon objet thread qui va gérer la boucle et la sortie du traitement

Aide de la fonction ThreadExecute :
Paramètres à passer à la procédure. Attention ces paramètres sont
passés par valeur (et non par adresse)

--> Résultat : dans la procédure je me retrouve avec une copie de mon
objet
Avatar
Daireaux Jean-Baptiste
Alex a écrit :
Bonjour, j'expérimente l'utilisation des threads.
Je souhaite les gérer via une classe.

J'arrive à lancer les threads qui font les calculs en //.
Mon souci c'est pour les arrêter.

J'ai un bouton dans la fenêtre (thread principal) qui appelle la methode
oT:mbFin() pour le stopper.
L'attribut :abFin de l'objet est mis à vrai.
Dans le traitement en boucle (thread secondaire),
je lis l'attribut :abFin (oT:mbBoucle()) et je suis sencé sortir de la
boucle. ce qui devrait terminer le thread.

Hors quand je mets :abFin à vrai dans le thread principal,
il est toujours à Faux dans le thread secondaire !!!

D'ou ma question :
comment faire pour partager un objet de classe entre deux threads?

Merci pour vos lumières,

Alex

...
cThread est une classe

PUBLIQUE CONSTANT

asNom est une chaîne // oThread_13

// Arret
abFin est un booléen
abBoucle est un booléen

GLOBAL CONSTANT

// Tous les threads
gtListe est un tableau associatif de cThread

FIN
...



Bonjour,

essai -> gtListe est un tableau associatif de cThread dynamique

au sinon ici :
PROCEDURE mbInitialise()

:asNom = "oThread_"+DonneIdentifiant()
::gtListe[:asNom] = objet <<< ICI je croit que cela copie...

RENVOYER Vrai


J'espere que c'est la bonne piste.
J.B.D.