在c中设置跳转和跳远代码流

set jump and long jump codeflow in c

我正在尝试学习 C 中的 setjump 和 longjump。任何人都可以帮助我输出以下代码以及代码流和 cases.i 调用函数 funcall() 的解释在代码中。第一次迭代调用警报,但在后续迭代中未调用警报。为什么会这样? alarm(0) 是否会阻止任何未来的警报请求?

编辑:即使删除了信号处理程序中的 "print_T()" 行,代码似乎也没有 运行。

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

#define LEN 50

jmp_buf po;

void print_T() {
    time_t rawtime;
    struct tm * timeinfo;

    time(&rawtime);
    timeinfo = localtime ( &rawtime );
    printf ( "Current local time and date: %s", asctime (timeinfo) );
}



static void ti() {
    print_T();
    longjmp(po,1);
}
int funcall(int reply) {


    static int p;
    p = 0;
    signal(SIGALRM, ti);
    int q = setjmp(po);
    if(q == 0)  
        printf("the value BEFORE setjmp %d for reply %d\n", p, reply);
    else 
        printf("the value AFTER setjmp %d for reply %d\n", p, reply);
    alarm(5);

    if(p > 0) {
        printf("INVOKING THE ALARM");
        alarm(0);
        return -1;
    }

    p++;    
    for(int i = 0; i < 100000; i++) 
        for(int j = 0; j < 100000; j++);
    return 0;

}

int main() {

    int a;
    int reply;
    time_t start, end;
    for(reply=0; ; reply++) {
        printf("~~~~~~~~~~~~~~~~~~~~~~~~~ITERATION NUMBER  %d\n", reply);

        time(&start);
        a = funcall(reply);
        time(&end);
        double tin = difftime(end, start);
        printf("*********************ITERATION END  and a returned is %d after %f\n", a, tin );
        double tidiff = difftime(end, start);
        if(a < 0)
            if(reply == 10) {
                break;
           }

    }

}

由于我的声誉低于 50,因此我不能对除我以外的任何 post 发表评论,这里是您的代码在 mac [=66= 上执行时的输出]:

我没有发现您的代码有任何问题,因为 alarm(5) 的调用次数与 funcall() 的调用次数一样多。

每次调用 funcall(),第一次调用 alarm(5) 设置 SIGALRM 信号传递给调用进程(它只不过是函数正在 executed/thread 执行函数)在 5 秒后执行代码的其余部分。

因为在每次调用funcall()静态变量时p被设置为0,if(p > 0){...}块将不会被执行直到p大于 0,仅当执行此块主体之后的下一条语句 p++ 递增 p 并使其大于零时才会发生。

前面提到的 if 块的执行和因此对 alarm(0) 的调用取决于 p++ 之后的 for 循环所花费的时间终止。如果 for 循环的执行在 5 秒内完成,return 0 语句将 return 控制权交给调用函数。 return 将取消所有报警请求并销毁函数调用堆栈。因此,在这种情况下 alarm(0) 不会被调用。

接下来,如果 for 循环的执行时间 > 5 秒(忽略所有可能发生的调度延迟,有时可能会导致意外行为),将触发未决警报,从而调用信号处理程序 ti()。当调用信号处理程序 ti() 时,将调用 longjump() 并在 setjump() 的调用指令处再次开始执行。当控制到达 alarm(0) 时(假设 for 循环持续执行,只要前面的 if 块没有第二次执行),所有剩余的警报请求都被取消通过这个电话。因此,alarm(0) 在 p>0 和 for 循环时间超过 5 秒后取消所有未决警报请求。

这里是通过asciinema记录的执行 https://asciinema.org/a/fyZX7CRoikq5kLJS2t0Og2rot

这是执行完成后 asciinema 会话的屏幕截图。