проблема с setjmp и longjmp для переключения между 2 функциями - PullRequest
0 голосов
/ 10 марта 2020

Я пытаюсь реализовать код, который непрерывно переключается между функциями fun () и main (), которые ничего не делают, кроме бесконечной печати на экране. Я пытаюсь переключиться с помощью setjmp и longjmp и использую сигнал SIGALRM в C. Но когда я запускаю его, он просто работает один раз, а затем не переключается.

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>

jmp_buf b1, b2;
int cur = 0;

void handlesig(int sig) {
    if(!cur) {
        cur = 1;
        setjmp(b2);
        longjmp(b1, 1);
    }
    else {
        cur = 0;
        setjmp(b1);
        longjmp(b2, 1);
    }
}

void fun() {    
    while(1) {
        printf("I am in function fun()\n");
        for(int x = 0; x < 100000000; x++);
    }
}

int main() {    
    signal(SIGALRM, handlesig);
    ualarm(900000, 900000);                     //send SIGALRM after each 900000 microseconds
    if(!setjmp(b1))
        fun();                                  //will be run when setjmp returns 0
    while(1) {                      
        printf("I am in function main()\n");    //will be run when setjmp returns 1
        for(int x = 0; x < 100000000; x++);
    }
    return 0;
}

Я не понимаю, в чем проблема с этим кодом.

1 Ответ

1 голос
/ 10 марта 2020

Ваша программа имеет неопределенное поведение, поскольку время жизни блока, в котором setjmp был вызван b1 или b2 в обработчике сигналов, заканчивается, как только вызывается longjmp (в самой следующей строке). В следующий раз, когда вы вызываете longjmp, пытаясь вернуться к jmp_buf, который больше не действителен, поведение не определено, и это проявляется в том, что состояние полностью повреждено.

Вы можете написать a взломайте , чтобы обойти это, используя флаг sigaltstack и SA_ONSTACK, чтобы обработчик сигнала имел несколько стеков, так что даже если jmp_buf формально недействителен, на практике он не засорен. Но это не действительная программа, просто она работает на практике в некоторых системах (не во всех). В конечном счете, нет (действительного / надежного) способа сделать то, что вы просите, с помощью setjmp и longjmp; для переключения контекста требуется строго более сильный примитив, чем тот, который они предоставляют.

...