Question

J'ai ce projet scolaire et il s'agit d'utiliser SETJMP et LongJMP pour effectuer des calculs imprécis. Le programme démarre une minuterie qui signalera un gestionnaire de signaux.

Avant l'expiration de la minuterie, il y a un calcul itératif (à des fins de démonstration, juste une boucle ne faisant rien d'utile). Au début de cette boucle, il y a un appel setJMP, et dans le gestionnaire de signaux, il y a un appel longjmp. Cela force essentiellement la boucle à arrêter le calcul du milieu et à exécuter le gestionnaire de signaux où il appelle LONGJMP.

Le problème que j'ai, c'est que chaque fois que la partie de calcul est très courte, je semble que je me réduise de manière assez cohérente, mais lorsque la partie de calcul est longue (la boucle intérieure a de nombreuses itérations), elle fonctionne très bien (n'a pas encore rencontré de segfault) . De toute évidence, la segfault doit se produire dans les zones entourant cette section de calcul, mais je ne peux pas comprendre d'où elle vient du débogage change les choses que l'utilisation des instructions d'impression.

Voici le code que j'ai:

#include <iostream>
#include <signal.h>
#include <sys/time.h>
#include <setjmp.h>
#include <errno.h>
#include <stdlib.h>

jmp_buf env;


static void usr_timer_tick(int signal)
{
    if(signal == SIGALRM)
    {
        longjmp(env, 1);
    }
}


/*Program Description
 * This program first sets up the timer to signal usr_timer_tick
 * every 1 second on the SIGALRM signal. It then proceeds to do an iterated calculation three times.
 * An infinite loop calls setjmp and when 0 is returned, continues doing
 * a calculation on temp. After an iteration is complete, the result of
 * the iteration is saved into finalResult after blocking SIGALRM to
 * make the saving of the result atomic.
 *
 * Once the signal handler(usr_timer_tick) is triggered, it calls longjmp which forces
 * setjmp to return a non-zero value, which causes the main function to break out
 * of the infinite loop and start a new calculation...this is done a total of 3
 * times for demonstration purposes.
 */
int main(int argc, char **argv)
{

    //init timer using setitimer..real mode
    int which = ITIMER_REAL;
    struct itimerval value;
    struct sigaction sact;
    sigset_t newmask, oldmask;
    sigemptyset( &newmask );
    sigemptyset( &oldmask );
    sigaddset(&newmask, SIGALRM);

    sact.sa_flags = 0;
    sact.sa_handler = usr_timer_tick;
    sigaction( SIGALRM, &sact, NULL );
//    value.it_interval.tv_sec = 0;        /* One second */
//    value.it_interval.tv_usec = 0;
//    value.it_value.tv_sec = 1;           /* One second */
//    value.it_value.tv_usec = 0;
//
//    setitimer(which, &value, NULL);



    double finalResult = 0;
    int loopcount = 0;
    double tempResult = 0;
    for(int j = 0; j < 10; j++)
    {
        loopcount = 0;


            std::cout << "Run " << j << " begin loop "
            << loopcount << "\n";


            if(setjmp(env) == 0)
            {   //timer not hit yet

                //sigprocmask(SIG_BLOCK, &newmask, NULL);
                value.it_interval.tv_sec = 0;        /* One second */
                value.it_interval.tv_usec = 0;
                value.it_value.tv_sec = 1;           /* One second */
                value.it_value.tv_usec = 0;

                setitimer(which, &value, NULL);

                //sigprocmask(SIG_SETMASK, &oldmask, NULL);
                for(;;)
                {
                    //Do some random calculations
                    for(int i = 0; i < 1; i++)
                    {
                        tempResult = tempResult + .001;
                    }

                    //block signal from arriving and save to finalResult
                    if(sigprocmask(SIG_BLOCK, &newmask, NULL) < 0) exit(-1);
                    finalResult = tempResult;
                    std::cout << "Run " << j << " complete loop "
                        << loopcount << " result = " << finalResult<< "\n";
                    loopcount++;
                    if(sigprocmask(SIG_SETMASK, &oldmask, NULL)< 0) exit(errno);
                }
            }
            else
            {
                //timer signal arrived, print the final result and get out of loop
                std::cout << "***Run " << j << " killed on loop "
                        << loopcount << " result = "<< finalResult << "\n";
                sigprocmask(SIG_SETMASK, &oldmask, NULL);
                //break;
            }



    }
    return 0;
}

Je comprends que certains d'entre vous peuvent ne pas être d'accord pour dire que LongJMP devrait être utilisé dans un gestionnaire de signaux, mais c'est ainsi que mon professeur a dit de le faire. Il convient également de noter que je débloque le sigalrm après que le longjmp a été appelé (voir Else Statement of Main).

En regardant DMESG, je reçois:

 [121395.233842] cppapplication_[17397]: 
segfault at 2 ip b74656f6 sp bfbb5abc 
error 6 in libc-2.12.1.so[b743b000+157000

]

Était-ce utile?

La solution

Vous ne pouvez pas utiliser ´longjmp´ pour sortir d'un événement asynchrone comme une minuterie. Il est conçu uniquement pour enregistrer et restaurer les registres et le pointeur de pile qui sont enregistrés par la convention d'appel normale.

Note latérale: envisagez d'utiliser le volatile Mot-clé sur vos variables locales, comme spécifié dans 7.13.2.1:

Tous les objets accessibles ont des valeurs, et tous les autres composants de la machine abstraits ont un état, au moment où longjmp La fonction a été appelée, sauf que les valeurs des objets de durée de stockage automatique qui sont locaux à la fonction contenant l'invocation de la setjmp macro qui n'a pas volatil-type qualifié et ont été modifiés entre le setjmpinvocation et longjmp Les appels sont indéterminés.

Autres conseils

Votre gestionnaire de signaux va appeler longjmp, donc la cible de saut ferait mieux d'être valable. Cela signifie, appelez setjmp d'abord, puis sigaction et setitimer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top