信号 - SIGUSR1 class 练习
Signals - SIGUSR1 class exercise
我把它当作 class 练习。我不得不在没有 运行 的情况下分析输出,我认为
输出应该是 num=4。
但实际上这段代码在运行之后的输出是:
num=8
我很高兴知道我错过了什么?
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <termios.h>
int num = 0;
int y = 1;
void signal_hand(int sig) {
signal(SIGUSR1, signal_hand);
num = num + 1;
y = y * f();
}
int f() {
if (num == 2) {
return y;
}
pid_t pid = 0;
pid = getpid();
kill(pid, SIGUSR1);
return 2 * y;
}
int main(void) {
int x = 0;
signal(SIGUSR1, signal_hand);
x = f();
printf("num = %d\n", x);
return 1;
}
这是一个有趣的问题。
所以发生的事情是创建一个调用 f() 的信号处理程序,它会终止正在 运行ning 的程序。但是信号处理程序捕获它发出的相同信号。
每次程序被杀死时,它都会调用信号处理程序,并再次尝试杀死程序。这是递归自杀。这节目真想死
这将是一个永无止境的循环,除了它计算它被捕获其信号的次数以及当它被捕获 2 个信号时,计数为 num=2,它从 f 开始 returns () 没有第三次杀死自己。
所以要分解它是如何达到 8 的...
一共调用了3次f()。第一次,它被调用,它自杀了。它通过信号处理程序再调用自己 2 次。
这很难解释清楚。
- f() 调用的外层(这是开始 kill 递归的函数),这是最后一个完成的 f(),它从3) [下方] 并将其乘以 2,得到 8。它 returns.
这调用了以下内容,其中 运行 按顺序:
- f() 调用的内层(1 信号陷阱 in),returns 2,稍后在处理程序中乘以 y=1 得到 y=2。此函数在信号处理程序接收到第二个信号(如下)之前完成,并且是第一个完成的 f()。
- 2) 完成后。 f()调用的另一个内层(2个信号陷阱)returns 2,它开始的值。它随后乘以信号处理程序中的 y,即 2,得到 4。此时 Num=2。这是第二个完成的 f()。
现在那些“最后”两个步骤,我不认为是按顺序 运行,我认为如果 f() 中有更多处理,我们会看到信号会在陷阱 1 还在 运行ning 时被困在陷阱 2 中。但我认为我们在这里看到的是一个时间问题,陷阱 1 f() 在信号有时间发出之前立即完成,通过操作系统并 return 到应用程序由信号处理程序。
这是一个邪恶的问题。我认为这个问题的重点是当你在 C 中捕获一个信号时,程序并没有死,它仍然非常活跃。而且它也可以被多次杀死,信号处理完全控制程序做什么以及它如何关闭。
举一个为什么有用的例子,想象一个 linux 数据库通过 SHM 或其他方式习惯性地驻留在 RAM 中。如果你想关闭 PC 或其他东西,操作系统会向程序发送终止信号。大多数程序会忽略这一点,然后死掉,但是数据库可能不会死掉,因为它可能会丢失尚未写入磁盘的数据,因此在这种情况下,它可能想要捕获终止信号,然后刷新数据到磁盘,然后退出。
*注意我在这里说的是杀戮和死亡,但我只是注意到这是一个用户信号,但机制也与杀戮信号相似。
我把它当作 class 练习。我不得不在没有 运行 的情况下分析输出,我认为
输出应该是 num=4。
但实际上这段代码在运行之后的输出是:
num=8
我很高兴知道我错过了什么?
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <termios.h>
int num = 0;
int y = 1;
void signal_hand(int sig) {
signal(SIGUSR1, signal_hand);
num = num + 1;
y = y * f();
}
int f() {
if (num == 2) {
return y;
}
pid_t pid = 0;
pid = getpid();
kill(pid, SIGUSR1);
return 2 * y;
}
int main(void) {
int x = 0;
signal(SIGUSR1, signal_hand);
x = f();
printf("num = %d\n", x);
return 1;
}
这是一个有趣的问题。
所以发生的事情是创建一个调用 f() 的信号处理程序,它会终止正在 运行ning 的程序。但是信号处理程序捕获它发出的相同信号。
每次程序被杀死时,它都会调用信号处理程序,并再次尝试杀死程序。这是递归自杀。这节目真想死
这将是一个永无止境的循环,除了它计算它被捕获其信号的次数以及当它被捕获 2 个信号时,计数为 num=2,它从 f 开始 returns () 没有第三次杀死自己。
所以要分解它是如何达到 8 的...
一共调用了3次f()。第一次,它被调用,它自杀了。它通过信号处理程序再调用自己 2 次。
这很难解释清楚。
- f() 调用的外层(这是开始 kill 递归的函数),这是最后一个完成的 f(),它从3) [下方] 并将其乘以 2,得到 8。它 returns.
这调用了以下内容,其中 运行 按顺序:
- f() 调用的内层(1 信号陷阱 in),returns 2,稍后在处理程序中乘以 y=1 得到 y=2。此函数在信号处理程序接收到第二个信号(如下)之前完成,并且是第一个完成的 f()。
- 2) 完成后。 f()调用的另一个内层(2个信号陷阱)returns 2,它开始的值。它随后乘以信号处理程序中的 y,即 2,得到 4。此时 Num=2。这是第二个完成的 f()。
现在那些“最后”两个步骤,我不认为是按顺序 运行,我认为如果 f() 中有更多处理,我们会看到信号会在陷阱 1 还在 运行ning 时被困在陷阱 2 中。但我认为我们在这里看到的是一个时间问题,陷阱 1 f() 在信号有时间发出之前立即完成,通过操作系统并 return 到应用程序由信号处理程序。
这是一个邪恶的问题。我认为这个问题的重点是当你在 C 中捕获一个信号时,程序并没有死,它仍然非常活跃。而且它也可以被多次杀死,信号处理完全控制程序做什么以及它如何关闭。
举一个为什么有用的例子,想象一个 linux 数据库通过 SHM 或其他方式习惯性地驻留在 RAM 中。如果你想关闭 PC 或其他东西,操作系统会向程序发送终止信号。大多数程序会忽略这一点,然后死掉,但是数据库可能不会死掉,因为它可能会丢失尚未写入磁盘的数据,因此在这种情况下,它可能想要捕获终止信号,然后刷新数据到磁盘,然后退出。
*注意我在这里说的是杀戮和死亡,但我只是注意到这是一个用户信号,但机制也与杀戮信号相似。