【发布时间】:2019-12-20 04:39:13
【问题描述】:
我正在尝试实现 shell 中存在的一些功能,包括仅在用户输入 quit 而不是 Ctrl+C 时退出。下面是我尝试过的代码的简化版本。
代码 1:没有在信号处理程序中调用 loop()。
void loop(){
while(1){
char a[20];
printf("Enter Command : " );
scanf("%s",a);
printf("%s\n", a);
}
}
void sigintHandler(int sig_num)
{
signal(SIGINT, sigintHandler);
printf("\n");
}
int main(int argc, char const *argv[]) {
signal(SIGINT, sigintHandler);
loop();
return 0;
}
代码1的输出:
从第三个输入可以看出,我转到一个新行并从我离开循环的地方继续。我想重新开始循环。因此,我通过在信号处理程序本身中调用循环进行了以下修改。
void loop(){
while(1){
char a[20];
printf("Enter Command : " );
scanf("%s",a);
printf("%s\n", a);
}
}
void sigintHandler(int sig_num)
{
signal(SIGINT, sigintHandler);
printf("\n");
loop();
}
int main(int argc, char const *argv[]) {
signal(SIGINT, sigintHandler);
loop();
return 0;
}
代码 2 的输出:
可以看出,当我第一次单击 Ctrl+C(在输入第 3 行上)时,它可以正常工作,我可以继续。但是当我第二次单击 Ctrl+C 时,我没有转到新行,我必须按 enter 才能执行程序。
我处理了this 的问题,但它似乎不适用于我的情况。这是我第一次使用信号和系统调用,所以我的问题可能很愚蠢。但是,如果有人可以帮助我找到实现信号的正确方法,那将是一个很大的帮助。谢谢。
【问题讨论】:
-
不要使用
signal()——使用sigaction()(见What is the difference betweensigaction()andsignal()?)。不要在信号处理程序中使用printf();它可能导致未定义的行为(请参阅How to avoid usingprintf()in a signal handler)。不要在信号处理程序中使用loop()——这是完全不支持的。 -
@J.Panek:
signal()的某些变体重置信号处理程序并要求信号处理程序恢复信号处理。在sigaction()中查找SA_RESETHAND,这在很大程度上允许使用sigaction()模拟古董signal()实现。标准 C 中signal()的语义是最小的; POSIX 中signal()的语义反映了在 POSIX 标准化之前实际实现的分歧。 POSIX 推荐sigaction()有很多原因。 -
当您在信号处理程序中有
loop()调用时,您可能会发现中断信号仍然被阻塞,因为您还没有从原始信号处理程序返回。此外,在信号处理程序中调用loop()意味着您正在递归调用loop()(尽管是间接递归)。对loop()的原始调用也没有结束。您的loop()没有错误检查;我希望那是因为您创建了一个 MCVE (Minimal, Complete, Verifiable Example?)(或 MRE 或 SO 现在使用的任何名称)。 -
你应该注意
scanf()的返回值。如果它被中断,它可能会返回一个错误条件——如果它被中断,你不应该使用a中的值。 -
看看
scanf()返回了什么。如果它显示1,则可以使用a的内容。如果它显示0或EOF,您还有更多工作要做。此后,您可能需要使用clearerr(stdin)从终端获取任何有意义的信息。然后您可以返回并再次提示。
标签: c shell operating-system signals