在c中设置跳转和长跳码流

时间:2017-11-15 10:08:04

标签: c setjmp

我正在尝试在C中学习setjump和longjump。任何人都可以帮助我输出以下代码以及代码流和case.i在代码中调用函数funcall()。第一次迭代会调用警报,但在后续迭代中不会调用警报。为什么会这样?警报(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;
           }

    }

}

1 个答案:

答案 0 :(得分:1)

由于我的信誉小于50,因此我无法评论除我之外的任何帖子,以下是您在mac os上执行代码时的输出:

我发现您的代码没有任何问题,因为调用alarm(5)funcall()被调用了很多次。

对于funcall()的每次调用,首先调用alarm(5) SIGALRM 信号设置为传递给调用进程(这只是正在执行的函数/线程)执行该功能)5秒后执行代码的剩余部分。

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

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

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

以下是通过 asciinema 记录的执行情况 https://asciinema.org/a/fyZX7CRoikq5kLJS2t0Og2rot

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

screen shot of output from asciinema session