Arrêt d'une commande

Librairie C++ de calcul formel/ C++ symbolic computation library

Modérateur : xcasadmin

loic
Messages : 168
Inscription : ven. mars 14, 2008 7:20 pm

Arrêt d'une commande

Message par loic » lun. avr. 30, 2012 5:42 pm

Bonsoir,

je teste à présent l'interruption d'une commande.

En gros, voici comment sont initialisées les choses au début de mon programme.

Code : Tout sélectionner

    signal(SIGINT,giac::ctrl_c_signal_handler);
    giac::child_id=1;
    context=new giac::context;
puis lors de l'évaluation d'un gen:

Code : Tout sélectionner

  giac::ctrl_c=true;
  answer=protecteval(expression,25,context);
Il me semblait que pour interrompre la tâche, il fallait utiliser giac::kill_thread(true,context);
J'ai essayé, par exemple sur des commandes du style:

Code : Tout sélectionner

 factor(x^3213-2)
mais rien ne se produit...ça ne semble pas fonctionner, donc une seule question: Quelle est la marche à suivre?

parisse
Messages : 5881
Inscription : mar. déc. 20, 2005 4:02 pm
Contact :

Re: Arrêt d'une commande

Message par parisse » lun. avr. 30, 2012 8:18 pm

c'est malheureusement plus compliqué, il faut créer un thread ce que ne fait pas protecteval, j'essaierai d'expliquer ça demain, trop tard pour ce soir...

parisse
Messages : 5881
Inscription : mar. déc. 20, 2005 4:02 pm
Contact :

Re: Arrêt d'une commande

Message par parisse » mar. mai 01, 2012 3:25 pm

Bon, alors une petite description pour make_thread:

Code : Tout sélectionner

// create a new thread for evaluation of g at level level in context
  bool make_thread(const giac::gen & g,int level,const giac_callback & f,void * f_param,const context * contextptr)
Ca cree un thread séparé pour évaluer g, et ça quitte la fonction tout de suite (avant que g ne soit évalué si c'est un peu compliqué). Le paramètre f sert à indiquer ce qu'on doit faire lorsque le thread est terminé (et f_param désigne l'argument de f). Chaque pointeur de contexte peut avoir un thread d'évaluation en cours d'exécution et pas plus.
Une fois le thread créé, on peut vérifier pour chaque pointeur de contexte le statut du thread d'évaluation attaché avec check_thread (juste en-dessous de make_thread dans global.cc), check_thread appelle alors le callback si le thread est terminé. Il vérifie aussi si on a demandé l'arrêt du thread (test de kill_thread(contextptr)) et tue le thread si demandé.
Pour le multi-session, chaque session a son pointeur de contexte et il peut y avoir plusieurs évaluations simultanément, la liste des contextes est dans context_list et check_threads(int premier_index) va faire un check pour chaque thread de la liste à partir du numéro premier_index.

loic
Messages : 168
Inscription : ven. mars 14, 2008 7:20 pm

Re: Arrêt d'une commande

Message par loic » mar. mai 01, 2012 5:53 pm

Ok, merci des indications.
Tout n'est pas clair mais je vois déjà que je vais devoir modifier certains aspects de mon programme. Je lançais l'évaluation dans un thread séparé de mon côté.
Une fois ce thread terminé, il renvoyait un signal qui provoquait l'affichage à l'écran.
Je m'aperçois, au final, que ce n'est pas à moi de créer ce thread mais que je dois déléguer le travail à giac.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
En résumé si j'ai bien compris:

** On appelle make_thread avec les bons paramètres.
Ceci me crée une tâche d'évaluation du gen.

** Parallèlement, je crée une deuxième tâche qui, elle est censé superviser la première à coup de check_thread
(genre vérification toutes les demies secondes??)

** Si check_thread renvoie 0, il appellera la fonction de callback automatiquement. (En gros ma fonction d'affichage du gen ... généré après évaluation)
** Sinon, il ne se passe rien, sauf si toutefois entre temps, la boucle d'événements principale a appelé kill_thread. Et alors, la tâche est flinguée.

ça serait gen...ial si c'est bien comme cela que ça doit se passer!

PS: l'entier level, je dois le mettre à combien?

parisse
Messages : 5881
Inscription : mar. déc. 20, 2005 4:02 pm
Contact :

Re: Arrêt d'une commande

Message par parisse » mar. mai 01, 2012 8:16 pm

à 1 ou à DEFAULT_EVAL_LEVEL

loic
Messages : 168
Inscription : ven. mars 14, 2008 7:20 pm

Re: Arrêt d'une commande

Message par loic » mer. mai 02, 2012 9:07 am

Dernière question sur ce sujet (j'espère!):

make_thread renvoie un booléen, on le récupère où le gen évalué?

loic
Messages : 168
Inscription : ven. mars 14, 2008 7:20 pm

Re: Arrêt d'une commande

Message par loic » mer. mai 02, 2012 9:12 am

Je me réponds à moi-même:

Par hasard, le gen évalué se trouverait pas dans le premier argument g de la fonction de callback?
et le nouveau context (en cas de modif lors de la commande ) dans le deuxième argument newcontext

c'est bien ça?

parisse
Messages : 5881
Inscription : mar. déc. 20, 2005 4:02 pm
Contact :

Re: Arrêt d'une commande

Message par parisse » mer. mai 02, 2012 10:29 am

loic a écrit :Je me réponds à moi-même:

Par hasard, le gen évalué se trouverait pas dans le premier argument g de la fonction de callback?
et le nouveau context (en cas de modif lors de la commande ) dans le deuxième argument newcontext

c'est bien ça?
Le gen evalue est en effet le 1er argument de la fonction de callback, j'aurais du le preciser. Le 2eme argument est laisse a la disposition du programmeur, dans xcas je m'en sers comme pointeur sur le widget qui a lance la commande (ca permet de savoir ou il faut mettre la reponse).

loic
Messages : 168
Inscription : ven. mars 14, 2008 7:20 pm

Re: Arrêt d'une commande

Message par loic » mer. mai 02, 2012 11:48 am

Désolé, là je bloque à cause de ma faible pratique du c++.

j'ai un problème lors de l'appel à make_thread

Voici un extrait de mon code.
J'ai une classe CasManager qui est censé gérer l'essentiel des relations avec la librairie Giac.

Code : Tout sélectionner

// Ma fonction de callback
void CasManager::callback(const giac::gen & g,void * newcontextptr) {
    answer=g;
}
// Fonction d'évaluation du gen contenu dans la variable "expression"
void CasManager::evaluate(){
    giac::ctrl_c=true;
    if (make_thread(expression,giac::DEFAULT_EVAL_LEVEL,CasManager::callback,(void*)context,context))
    {
          // Traitement
    }
    else {
         // Thread is already busy
    }
}
Lors de la compilation, j'ai le droit à cela:
../qcas/qt/CasManager.cpp: In member function 'void CasManager::evaluate()':
../qcas/qt/CasManager.cpp:152:100: error: invalid initialization of reference of type 'void (* const&)(const giac::gen&, void*)' from expression of type '<unresolved overloaded function type>'
In file included from ../qcas/qt/MainWindow.h:22:0,
from ../qcas/qt/CasManager.h:20,
from ../qcas/qt/CasManager.cpp:22:
../qcas/giac/global.h:488:8: error: in passing argument 3 of 'bool giac::make_thread(const giac::gen&, int, void (* const&)(const giac::gen&, void*), void*, const giac::context*)'
../qcas/qt/CasManager.cpp: In member function 'OutputWidget* CasManager::formula2Widget(const QString&)':
../qcas/qt/CasManager.cpp:398:62: warning: format '%s' expects argument of type 'char*', but argument 2 has type 'const QChar*' [-Wformat]
../qcas/qt/CasManager.cpp: In constructor 'MonitorThread::MonitorThread(const giac::context*)':
../qcas/qt/CasManager.cpp:478:13: warning: invalid conversion from 'const giac::context*' to 'giac::context*' [-fpermissive]
make: *** [CasManager.o] Error 1
make: Leaving directory `/home/loic/qcas-build-Debug'
13:43:26: Le processus "/usr/bin/make" s'est terminé avec le code 2.
Erreur à la compilation du projet qcas (cible : )
Lors de l'exécution de l'étape "Make"
J'ai essayé de calquer sur votre code (background_callback dans threaded.cc) )mais visiblement il y a un truc que j'ai pas compris.
Une petite aide svp?

loic
Messages : 168
Inscription : ven. mars 14, 2008 7:20 pm

Re: Arrêt d'une commande

Message par loic » mer. mai 02, 2012 2:35 pm

Visiblement, le problème vient d'une différence entre les pointeurs de fonctions en C et les pointeurs de fonctions en c++.
Faudrait-il que ma méthode de callback soit statique?

parisse
Messages : 5881
Inscription : mar. déc. 20, 2005 4:02 pm
Contact :

Re: Arrêt d'une commande

Message par parisse » mer. mai 02, 2012 3:37 pm

le probleme c'est que le callback attendu est une fonction et pas une methode. En fait une methode c'est une fonction avec un pointeur en plus sur l'objet de la classe, c'est pour ca que ca ne marche pas, il faut donc simplement declarer (et implementer) le callback hors de la classe.

loic
Messages : 168
Inscription : ven. mars 14, 2008 7:20 pm

Re: Arrêt d'une commande

Message par loic » mer. mai 02, 2012 4:43 pm

Bon, les choses s'améliore.
Après restructuration complète de l'évaluation dans mon programme, le tout compile.

Pour cela:
** J'ai passé la méthode CasManager::callback(...) en statique, je ne suis pas obligé alors de la définir à l'extérieur de ma classe (plus simple pour moi).
** J'ai du décommenté dans config.h la ligne

Code : Tout sélectionner

/* Define to 1 if you have the `pthread' library (-lpthread). */
#define HAVE_LIBPTHREAD 1
(j'espère que j'ai bien fait.... Si c'est le cas, à noter pour les prochaines versions de qtgiac)

MAIS... (éh oui, il y a un "mais")
malheureusement, lorsque j'appelle kill_thread(context), ... toujours rien.... check_thread renvoie toujours 1.

Je récapitule ce que fait mon programme.
A l'initialisation:

Code : Tout sélectionner

   giac::child_id=1;
    signal(SIGINT,giac::ctrl_c_signal_handler);

    context=new giac::context;
   // Ca, c'est mon thread qui va surveiller à coup de checkThread(...) toutes les 50 ms si l'évaluation est finie
    monitor=new MonitorThread(context);
    logptr(new MyStream(this),context);
Lors du lancement de l'évaluation:

Code : Tout sélectionner

    giac::ctrl_c=true;
   if (giac::make_thread(expression,1,CasManager::callback,(void*)context,context))
    {
       disconnect(monitor,SIGNAL(finished()),mainWindow,SLOT(displayResult()));
        // On lance alors la surveillance de l'évaluation
        monitor->start();
       // On indique que lorsque le monitoring s'interrompt, l'affichage doit être lancé
        connect(monitor,SIGNAL(finished()),mainWindow,SLOT(displayResult()));
    }
Le bouton stop lance quant à lui l'instruction:

Code : Tout sélectionner

    giac::kill_thread(context);
Si vous voyez un truc qui m'a échappé....

parisse
Messages : 5881
Inscription : mar. déc. 20, 2005 4:02 pm
Contact :

Re: Arrêt d'une commande

Message par parisse » mer. mai 02, 2012 5:44 pm

En effet, il faut décommenter HAVE_LIBPTHREAD_H, mais ça ne marchera que sous unix, il faudra une version spécifique pour windows (de toutes facons le config.h actuel ne convient pas sous windows, comme Thomas Luka me l'a fait remarquer).
Pour kill_thread, c'est de ma faute, il faut faire
kill_thread(true,contextptr); ou kill_thread(contextptr)=true;

loic
Messages : 168
Inscription : ven. mars 14, 2008 7:20 pm

Re: Arrêt d'une commande

Message par loic » mer. mai 02, 2012 6:01 pm

Merci du conseil, on avance ... de problèles en problèmes mais je m'accroche! (J'espère que vous aussi!)

Voici mes tests et divers résultats:

Code : Tout sélectionner

factor(x^1237-2)
En trois essais, trois comportements aléatoires semble-t-il différents:

** J'ai un segfault qui est déclenché dans le fichier monomial.h ligne 119 (cela correspond à la ligne après le #else)

Code : Tout sélectionner

#ifdef _I386_   // a<-a+b*c mod m
    asm volatile("testl %%ebx,%%ebx; \n\t"
		 "jns .Lok%=\n\t"
		 "addl %%edi,%%ebx\n" /* a+=m*/
		 ".Lok%=:\t"
		 "imull %%ecx; \n\t" /* b*c in edx:eax */
		 "addl %%ebx,%%eax; \n\t" /* b*c+a */
		 "adcl $0x0,%%edx; \n\t" /* b*c+a carry */
		 "idivl %%edi; \n\t"
		 :"=d"(a)
		 :"a"(b),"b"(a),"c"(c),"D"(reduce)
		 );
#else
    a=(longlong(b)*c+a)%reduce;
#endif
  }
** J'ai eu le droit à un "aborted" (donc arrêt propre) avec un beau message de Giac
Thread 140736909768448 has been cancelled
** Un segfault dans modfactor.cc ligne 170

Code : Tout sélectionner

	      --(*itvptr); // decreases iterator to increase power of x to x^i
	      res += (it->val)*((*itvptr)->val);
Donc, comportement aléatoire mais on se rapproche semble-t-il.
Je rappelle, là je suis sur du 64 bits... je sais pas si ça peut influer.

loic
Messages : 168
Inscription : ven. mars 14, 2008 7:20 pm

Re: Arrêt d'une commande

Message par loic » mer. mai 02, 2012 6:08 pm

On est qd même de mieux en mieux.
Plusieurs essais avec ifactor au lieu de factor: aucun sefault et arrêt propre avec le message "Aborted"

Tiens, à noter que

Code : Tout sélectionner

ifactor(2^1231-2)

me renvoie:
Quadratic Sieve Failure. perhaps number too large.
Bad argument value
avec le message giac:
29320000 QSieve number of primes inf
Cas_setup [0,0,0,1,0,[1e-10,1e-15],12,[2,100,6,25],0,1,0]
Evaluation time: 0.99

Répondre