Arrêter une boucle en fonction des actions de l'utilisateur

Arrêter une boucle en fonction des actions de l'utilisateur - C++ - Programmation

Marsh Posté le 24-08-2004 à 17:03:22    

Salut,
 
alors, ça a peut-être déjà été traité, mais vu que la fonction recherche est en panne...
 
J'utilise Borland C++ Builder 6. Je fais un soft où l'utilisateur lance une méthode (en cliquant sur un bouton) qui peut durer (très) longtemps. Je voudrais donc avoir la possibilité d'annuler cette exécution.
 
Je vois pas trop comment faire, car il s'agit d'une boucle qui prend quasi 100% du CPU, et l'interface ne réagit plus aux actions.  
 
J'ai essayé de lancer la fonction dans une nouvelle Thread, mais je n'y connais rien et je me suis un peu paumé. J'ai testé _beginThread, ça marche, ça lance le calcul en tâche de fond, mais j'ai pas trouvé comment killer le thread...
 
Merci bcp


Message édité par deltaden le 24-08-2004 à 17:05:49
Reply

Marsh Posté le 24-08-2004 à 17:03:22   

Reply

Marsh Posté le 24-08-2004 à 17:19:55    

Il suffit de :
- utiliser une variable partagée entre le thread principal et l'autre thread  
- y coller la valeur qui va bien quand l'utilisateur dit stop
- tester de temps en temps dans le thread de calcul la valeur de la variable et agir en fonction

Reply

Marsh Posté le 24-08-2004 à 17:32:49    

pfff, oui, évidement... comment j'ai pas pensé à ça :??:
 
Merci bien  :jap:

Reply

Marsh Posté le 24-08-2004 à 18:02:23    

tu peux aussi mesure à chaque itération de la boucle mesurer depuis combien de temps tu est dans la boucle, et par exemple, toutes les secondes ou 1/4 de seconde aller retraiter la queue des messages.  
 
ça doit être un Application->ProcessMessages(), je sais plus sous C++ Builder.
 
pense aussi, lorsque tu lances un traitement, à inhiber les parties du GUI qui ne doit plus rien déclencher, car si dans ta boucle de traitement tu refais un tour périodiquement dan s la queue des messages, et que le bouton ayant lancé le traitement est recliqué, ton application devrait pêter les plombs.  
 
c'est aussi valable si tu passes par l'approche threadée (qui est potentiellement la meilleure)


Message édité par bjone le 24-08-2004 à 18:03:54
Reply

Marsh Posté le 24-08-2004 à 18:08:37    

Bon, en essayant de donner à _beginThread une fonction membre
de ma classe, ça donne ça:
[C++ Erreur] UnitMain.cpp(298): E2034 Impossible de convertir 'void (* (_closure )(void *))(void *)' en 'void (*)(void *)'
 
Ok, les signatures de méthodes ne correspondent pas...
En sortant ma méthode de ma classe, ça marche, mais c'est un peu laid, je dois donner comme paramètre l'instance de ma classe et accéder à toutes les variables internes.
 
C'est impossible d'appeller de cette manière une méthode appartenant à une classe ?
 
Edit: j'avais pas vu ton message bjone. je vais regarder à ça aussi.


Message édité par deltaden le 24-08-2004 à 18:10:37
Reply

Marsh Posté le 24-08-2004 à 18:19:03    

non, d'un point de vue bas niveau, quand une méthode de classe est appellée, elle recoit comme premier paramètre l'adresse de l'instance de classe (le this), comme paramètre implicite. (sauf pour les méthodes statiques)
 
il te faut une fonction "normale" qui appelles la méthode de l'instance qui va bien.
 
généralement quand tu crées un thread, tu as la fonction à appeller, et un paramètre à passer à la fonction.
 
il faut faire un truc du style:
 
class MaClasse
{
public:
    void MaMéthode();
};
 
ThreadFunction( DWORD Valeur ) // Valeur : paramètre passé à la création du thread
{
   MaClasse *Instance=reinterpret_cast<MaClasse *>(Valeur);
   Instance->MaMéthode;
}
 
à la création du thread:
 
MaClasse *MonTruc= ..... ;// ton instance de classe qui contient la méthode à threadifier
 
BeginThread/CreateThread() du style:
 
CreateThread( ThreadFunction, MonTruc ); // ptet à caster.
 
par contre je te dis ptet des bêtes: je raisonne par rapport aux implémétation classque des threads (surtout Win32), pas rapport ptet à ce qu'ils pourraient avoir rajoutés dans C++ Builder (mais tu peux utiliser les API Win32 si tu veux)
 
---
 
tu peux aussi faire une méthode statique, qui elle n'aura pas besoin d'instance:
 
class MaClasse
{
public:
    void MaMéthode();
     
    static void ThreadWrapper( DWORD Value ); // DWORD ou autre suivant le prototype des api de threading que tu utilises
};
 
et au niveau implémentation:
 
MaClasse::ThreadWrapper( DWORD Value )
{
    MaClasse *Instance=reinterpret_cast<MaClasse *>(Value);
     
    Instance->MaMéthode();
}


Message édité par bjone le 24-08-2004 à 18:22:44
Reply

Marsh Posté le 24-08-2004 à 18:34:42    

sinon pour arrêter le thread, tu ne le tues pas à la "porc", vue que ne sais pas dans quel état sera tes strutures. (tu ne fais pas un "kill" explicite du thread)
 
mais effectivement, tu utilises un flag (attention il faudra peut être mettre un ou plusieurs sémaphores), et la boucle de MaClasse::MaMéthode() devra être capable de s'arrêter proprement.
 
en sortant de la fonction de Thread, celui ci sera automatiquement supprimmé. (d'ailleurs la fonction de Thread doit retourner quelque chose à regarder dans la doc)

Reply

Marsh Posté le 24-08-2004 à 19:10:17    

on y va molo avec les cast sur les instances, sinon ça va partir dans le décor, vous allez rien comprendre

Reply

Marsh Posté le 24-08-2004 à 20:48:16    

ok, merci beaucoup bjone, j'étais arriver à qlqc de fonctionnel, mais pas aussi clair.
 
A priori, le ProcessMessage() est suffisant, je n'ai pas vraiment besoin de faire un second thread.  
De toute façon, même si toute l'interface est inutilisable pendant la mesure, ce n'est pas grave, car pendant cette période elle sert à rien.
Je crois que je vais simplement faire comme ça.
 
Enfin, j'ai appris quelque chose, c'est toujours utile :)


Message édité par deltaden le 24-08-2004 à 20:55:44
Reply

Marsh Posté le 24-08-2004 à 21:14:11    

Taz a écrit :

on y va molo avec les cast sur les instances, sinon ça va partir dans le décor, vous allez rien comprendre


 
le reinterpret_cast<> est adapté là non ?
 
(un à l'aller pour passer l'adresse d'un l'instance, et l'un au retour pour récupérer l'adresse de l'instance de manière transparente)


Message édité par bjone le 24-08-2004 à 21:15:00
Reply

Marsh Posté le 24-08-2004 à 21:14:11   

Reply

Marsh Posté le 24-08-2004 à 21:16:26    

deltaden a écrit :

ok, merci beaucoup bjone, j'étais arriver à qlqc de fonctionnel, mais pas aussi clair.
 
A priori, le ProcessMessage() est suffisant, je n'ai pas vraiment besoin de faire un second thread.  
De toute façon, même si toute l'interface est inutilisable pendant la mesure, ce n'est pas grave, car pendant cette période elle sert à rien.
Je crois que je vais simplement faire comme ça.
 
Enfin, j'ai appris quelque chose, c'est toujours utile :)


 
c'est pas tellement la notion d'utilitée ou pas, c'est que si l'utilisateur clique sur le même bouton qui va lancer ton traitement, tu vas avoir deux fois le même traitement sur le même jeu de donné (et un gros blam rapidement)


Message édité par bjone le 24-08-2004 à 21:16:52
Reply

Marsh Posté le 24-08-2004 à 21:21:04    

bjone a écrit :

le reinterpret_cast<> est adapté là non ?
 
(un à l'aller pour passer l'adresse d'un l'instance, et l'un au retour pour récupérer l'adresse de l'instance de manière transparente)

static_cast peut suffir si t'es sur de toi.

Reply

Marsh Posté le 24-08-2004 à 21:29:36    

bjone a écrit :

c'est pas tellement la notion d'utilitée ou pas, c'est que si l'utilisateur clique sur le même bouton qui va lancer ton traitement, tu vas avoir deux fois le même traitement sur le même jeu de donné (et un gros blam rapidement)


Je vois pas ce que ça change avec un thread: ça va lancer deux thread identique, ce qui dans mon cas va aussi tout faire planter.
 
De toute façon c'est pas un problème, une fois qu'on lance le traitement, le bouton se transforme en bouton annuler...

Reply

Marsh Posté le 24-08-2004 à 22:14:10    

Taz a écrit :

static_cast peut suffir si t'es sur de toi.


 
ok.

Reply

Marsh Posté le 24-08-2004 à 22:15:25    

deltaden a écrit :

Je vois pas ce que ça change avec un thread: ça va lancer deux thread identique, ce qui dans mon cas va aussi tout faire planter.
 
De toute façon c'est pas un problème, une fois qu'on lance le traitement, le bouton se transforme en bouton annuler...


 
ha ok, non, je disais juste ça au cas où ton bouton de lancement restait activé, si il passe en annuler et qu'en cliquant dessus ça coupe bien le traitement, c'est bon.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed