Controller l'execution d'une fonction [Résolu]

Signaler
Messages postés
8
Date d'inscription
dimanche 2 novembre 2008
Statut
Membre
Dernière intervention
19 novembre 2008
-
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
-
Salut,

je programme un interface graphique qui permette à un utilisateur de controler l'execution d'une fonction. Comme je suis débutant, j'ai trouvé plus facile d'utiliser les MFC plutot que les API. J'ai utilisé Visual studio pour m'aider à créer la fenetre principale et j'ai créé des menus. En particulier, un menu Run contenant les items : Start, Stop et Pause. Je voudrais que la fonction s'execute lorsque l'utilisateur clic sur Start, qu'elle se termine lorsqu'il appuye sur Stop et se suspende lorsqu'il appuye sur pause. Le soucis est que si je lance la fonction à partir de OnRunStart(), l'interface graphique est figé tant que la fonction ne se termine pas. (Dans mon cas, elle ne se termine jamais car elle contient une boucle.) Alors comment faire? En regardant un peu sur le forum, j'ai vu qu'on y parlait d'utiliser des threads, mais je ne sais pas trop ce que c'est, ni si cela s'applique à mon problème. (C'est mon premier programme pour Windows Javascript:Insert_Emoticon('/imgs2/smile_big.gif');)

Si quelqu'un pouvait me suggérer quelques solutions, ce serait sympa.

11 réponses

Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Ce n'est pas parce qu'un message arrive que l'exécution de OnIdle va s'arrêter. Il faut donc que ce que tu mettes dans OnIdle soit relativement court.
Messages postés
21042
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
25
Un long traitement se fait dans un thread séparé pour ne pas bloquer l'interface graphique qui est dans ton thread primaire.

ciao...
BruNews, MVP VC++
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Salut,

Un code qui illustre ce principe, mais dans une appli console :
http://www.cppfrance.com/forum/sujet-ARRETER-BOUCLE-INFINI_996556.aspx?p=2
Messages postés
21042
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
25
Il doit chercher des exemples avec AfxBeginThread().
En utilisant directement l'API, il n'aurait aucun constructeur ni destructeur de classe appelé donc graves fuites de mémoire.

ciao...
BruNews, MVP VC++
Messages postés
8
Date d'inscription
dimanche 2 novembre 2008
Statut
Membre
Dernière intervention
19 novembre 2008

Merci pour vos réponses. Je vais regarder de ce pas comment marchent les threads.

Cela dit, j'ai entretemps imaginé une autre stratégie et je voudrais avoir votre avis là dessus.
Au lieu de lancer ma fonction à partir de OnRunStart(), je n'utilise OnRunStart() que pour assigner une valeur arbitraire START à une variable m_run. Je passe ensuite cette variable à la fonction OnIdle() [membre de ma classe "Application"] et je lance ma fonction à partir de OnIdle() si m_run ==START. De cette manière ma fonction tourne en boucle tant qu'il n'y a pas de nouveaux messages (ce que je veux) et répond à chaque injonction Start, Stop ou Pause.
Est-ce que cette solution est meilleure ou moins bonne que d'utiliser une nouvelle thread? Qu'en pensez-vous?
Messages postés
8
Date d'inscription
dimanche 2 novembre 2008
Statut
Membre
Dernière intervention
19 novembre 2008

Salut à tous,

J'ai essayé les threads et ca marche très bien. Je lance la thread secondaire avec AfxBeginThread(), je mets l'application en pause avec SuspendThread() et la réactive avec ResumeThread(). Par contre, je le plus grand mal du monde à trouver une façon d'intérompre la thread. Pourquoi n'y a -t-il pas une gentille fonction qui fait ce boulot là ? (Enfin, autre que TerminateThread() car celle-là ne nettoie derrière elle).

Qui sait comment faire cette opération ?
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Il n'y a pas de recette miracle. Il faut faire un teste régulièrement dans la routine du thread. Cela peut se faire via un évènement (Voir l'exemple de mon lien plus haut), ou simplement par une variable globale, passant de 0 à 1. Sachant que la variable en question n'est écrite que par le thread principal, il n'y a pas à s'embêter concernant la concurrence d'accès.

Tout le problème étant de tester très régulièrement si l'arrêt du thread a été demandé... Donc à chaque tour de boucle des principales boucles de la routine du thread par exemple :

// Premier traitmement
for (i = 0; i < n ; i++)
{
  // Traitement
  // Fin du thread demandé par le thread principal
}

// Deuxième traitement
while (une condition && fin du thread pas demandée)
{
  // Traitement
}

Une fois que le thread principal à demandé au thread secondaire de s'arrêter, en pur Win32, il faut que le thread principal attende que le thread secondaire s'arrête pour fermer proprement son handle sur le thread secondaire. Je ne sais pas comment cela doit se traduire en MFC, mais je serais surpris qu'il ne faille pas que le thread principal attende le thread secondaire.
Messages postés
8
Date d'inscription
dimanche 2 novembre 2008
Statut
Membre
Dernière intervention
19 novembre 2008

Je crois que je comprend le principe de l'arret par une variable ou un event (CEvent). C'est lorsque j'essaye de l'appliquer que ca foire.


La fonction que je veux executer dans un thread secondaire doit recevoir des parametres. Or ces parametres sont determines par l'utilisateur dans une boite de dialogue non modale. En clair, ces parametres sont des membres proteges d'une classe de dialogue. Avant que vous ne m'aiguiyiez vers les conditions d'arret, j'utilisais le pointeur pParam de AfxBeginThread(funcProc, pParam, ....) pour pointer vers ma classe de dialogue pour acceder a ces variables, mais maintenant je dois l'utiliser pour passer un 'event'. Du coup, je me suis dit pourquoi ne pas faire ma function funcProc membre de la classe de Dialogue. C'est meme plus logique. Mais la ca ne marche plus (erreurs de compilation). Voici comment mon code principal est structure:

Dans mon Document.cpp:




#include monDialog.cpp //De cette maniere j'ai les declarations et les definitions des fonctions





/// Plein de code .........




void
CdmdControllerDoc::OnRunStart()



if
((m_Program !=NONE)&& (m_Run!=START))
{
m_Run=START;


//Create the thread (pDlg est un pointeur vers mon dialogue)

m_pWorkThread =AfxBeginThread(pDlg->funcProc, pParam,THREAD_PRIORITY_LOWEST); // pParam sera vraisemblablement un CEvent*
}




void
CdmdControllerDoc::OnRunStart()



if
((m_Program !=NONE)&& (m_Run!=STOP)
   {
   m_Run=STOP;


   //Faire ce qui s'impose pour dire a la thread secondaire de se terminer


   }





void




CdmdControllerDoc::OnRunPause()
{


if
(m_Run!=PAUSE)
   {   
      m_Run=PAUSE;
      m_pWorkThread->SuspendThread();


   }


else
   
{
      m_Run=START;
      m_pWorkThread->ResumeThread();
   }
}




 Dans mon monDialogue.cpp

// This is the function that implements the Test program
UINT CmonDialog::funcProc(LPVOID pParam)
{
_cprintf("I'm in Prog_Test");
int i=0;
for (i=0;i<1e5;i++)
{_cprintf("%d",i);
}
return 0;
}



Visual Studio me donne le message d'erreur





error C3867: 'CmonDialog::funcProc': function call missing argument list; use '&CmonDialog::funcProc' to create a pointer to member




Que faut-il faire dans ce cas la?




Quand j'aurai fini par faire marcher cette thread, il faudra que je poste un exemple car ca manque cruellement.
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
'CmonDialog::funcProc': Appel de fonction sans liste d'argument. Utiliser '&CmonDialog::funcProc' pour créer un pointeur sur le membre.

Dans ton cas tu veux effectivement un pointeur sur le membre :

m_pWorkThread =AfxBeginThread(&CmonDialog::funcProc, pParam,THREAD_PRIORITY_LOWEST);
Messages postés
8
Date d'inscription
dimanche 2 novembre 2008
Statut
Membre
Dernière intervention
19 novembre 2008

Ajouter un & est la première chose que j'ai essayée et ca ne marche pas.

Curieusement, si funcProc n'est pas membre de ma classe CmonDocument ça fonctionne très bien. Le truc est alors de passer le pointeur 'this' en lieu et place de pParam pour pouvoir accéder aux variables publiques de CmonDocument (et à coup d'accesseurs aux variables privees). Ca fonctionne mais ce n'est pas tres elegant. Et puis ca ne resout pas vraiment le probleme original: comment je fais pour passer mes events?

Cordialement
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Il ne faut pas simplement mettre un &.

Il faut faire comme VS6 le propose, et comme je l'ai écrit dans mon poste.

Il faut mettre le nom de la classe, deux fois deux points, le nom de la méthode.

Pour ce qui est de passer quoique ce soit au thread, tu peux lui passer un pointeur. Autrement TOUT et n'importe quoi c'est à toi de voir.

En général, on passe l'adresse d'une structure contenant les éléments dont on a besoin. La structure peut contenir des pointeurs sur des classes c'est pas un problème.

Le tout est de faire un peu attention à ce que l'on fait (Pas passer de pointeur sur un objet local à une méthode si la méthode se termine avant la fin du thread, tout ça tout ça...)