我已经在Linux中一直在研究的信号。 而我做了一个测试程序来捕捉SIGINT。
#include <unistd.h>
#include <signal.h>
#include <iostream>
void signal_handler(int signal_no);
int main() {
signal(SIGINT, signal_handler);
for (int i = 0; i < 10; ++i) {
std::cout << "I'm sleeping..." << std::endl;
unsigned int one_ms = 1000;
usleep(200* one_ms);
}
return 0;
}
void signal_handler(int signal_no) {
if (signal_no == SIGINT)
std::cout << "Oops, you pressed Ctrl+C!\n";
return;
}
虽然输出如下所示:
I'm sleeping...
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
I'm sleeping...
I'm sleeping...
据我所知,按下Ctrl + C时,处理在前台进程组中的所有接收信号情报(如果没有进程选择忽略它)。
那么,这使得外壳(bash)的和上述程序的实例都接收到的信号? 哪里的“^ C”之前每个“哎呀呀”从何而来?
该操作系统是CentOS的,而shell是bash。
它是截获^ C,并将其转换为发送到连接的过程的信号(其是壳)的终端(驱动程序) stty intr ^B
将指示终端驱动程序拦截^ B代替。 它也是呼应了^ C回到终端的终端驱动程序。
壳仅仅是位于在线路的另一端的过程中,并接收它的从终端经由端子驱动器标准输入(例如/ dev / ttyX),并且它的标准输出(和stderr)也连接到相同的TTY 。
需要注意的是(如果启用呼应)终端发送击键到两个处理(组)并返回到终端。 stty命令只是包装器的ioctl()函数,用于“控制” TTY的过程tty驱动。
UPDATE:要证明外壳不参与,我创建了下面的小程序。 应该通过经由它的父shell执行exec ./a.out
(它显示一个交互式shell将叉女儿壳,反正)程序设置一个产生^ B,开关回声关闭SIGINTR关键,并且比等待从标准输入。
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
int thesignum = 0;
void handler(int signum);
void handler(int signum)
{ thesignum = signum;}
#define THE_KEY 2 /* ^B */
int main(void)
{
int rc;
struct termios mytermios;
rc = tcgetattr(0 , &mytermios);
printf("tcgetattr=%d\n", rc );
mytermios.c_cc[VINTR] = THE_KEY; /* set intr to ^B */
mytermios.c_lflag &= ~ECHO ; /* Dont echo */
rc = tcsetattr(0 , TCSANOW, &mytermios);
printf("tcsetattr(intr,%d) =%d\n", THE_KEY, rc );
printf("Setting handler()\n" );
signal(SIGINT, handler);
printf("entering pause()\n... type something followed by ^%c\n", '@'+THE_KEY );
rc = pause();
printf("Rc=%d: %d(%s), signum=%d\n", rc, errno , strerror(errno), thesignum );
// mytermios.c_cc[VINTR] = 3; /* reset intr to ^C */
mytermios.c_lflag |= ECHO ; /* Do echo */
rc = tcsetattr(0 , TCSANOW, &mytermios);
printf("tcsetattr(intr,%d) =%d\n", THE_KEY, rc );
return 0;
}
intr.sh:
#!/bin/sh
echo $$
exec ./a.out
echo I am back.
外壳相呼应,你输入的一切,所以当你键入^C
,即得得到呼应(和你的情况通过信号处理程序截获)。 该命令stty -echo
可能会或可能不会根据您的需要/约束是对你有用,看到了stty的手册页了解更多信息。
在较低的水平,当然更推移, 任何时候你经由外围设备的设备驱动程序与系统通信(如您使用以产生^ C信号键盘驱动程序,以及显示一切终端驱动程序)参与。 如果你想理解下面的书籍更详细,深入的级别是开始的好地方,你可以挖在汇编/机器语言,寄存器,查找表等的水平甚至更深:
Unix的OS的设计是这些形式的东西一个很好的参考。 两个比较经典引用: Unix的编程环境和UNIX环境高级编程
在这所很好的总结SO问题如何按Ctrl-C终止子进程?
“什么时候你运行一个程序,例如find
,外壳:
- 外壳本身叉
- 并为孩子设置默认的信号处理
- 与给定的命令替换子(例如与find)
- 当您按下CTRL-C,父shell处理这个信号,但孩子将收到它 - 用默认的动作 - 终止。 (孩子能实现信号处理过)”