我正在尝试在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;
}
}
}
答案 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)
取决于for
后p++
循环终止所花费的时间。如果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会话的屏幕截图。