先决条件: Fork系统调用 , 等待系统调用 信号是软件生成的中断,当用户按下ctrl-c或另一个进程告诉该进程某些信息时,操作系统会将其发送到进程。 有一组固定的信号可以发送到进程。信号由整数标识。 信号号有符号名称。例如 西格尔德 子进程终止时发送给父进程的信号数。 例如:
#define SIGHUP 1 /* Hangup the process */ #define SIGINT 2 /* Interrupt the process */ #define SIGQUIT 3 /* Quit the process */ #define SIGILL 4 /* Illegal instruction. */ #define SIGTRAP 5 /* Trace trap. */ #define SIGABRT 6 /* Abort. */
信号的操作系统结构
- 对于每个进程,操作系统维护2个整数,其位对应于一个信号号。
- 这两个整数跟踪: 等待信号和阻塞信号
- 使用32位整数,最多可以表示32个不同的信号。
例子: 在下面的示例中,SIGINT(=2)信号被阻塞,没有信号处于挂起状态。
一个信号被发送到一个进程,该进程在挂起的信号整数中设置相应的位。每次操作系统选择要在处理器上运行的进程时,都会检查挂起的整数和阻塞的整数。如果没有挂起的信号,进程将正常重新启动,并在下一条指令中继续执行。
如果有一个或多个信号处于挂起状态,但每个信号都被阻塞,则进程也会正常重新启动,但信号仍被标记为挂起。如果有一个或多个信号处于挂起状态且未被阻止,操作系统将执行进程代码中的例程来处理这些信号。
默认信号处理程序
有几个默认的信号处理程序例程。每个信号都与其中一个默认处理程序例程相关联。不同的默认处理程序例程通常具有以下操作之一:
- 忽略信号;i、 e.什么也不做,只是回来
- 期限:终止流程
- Cont:取消阻止已停止的进程
- 停止:阻止进程
// CPP program to illustrate // default Signal Handler #include<stdio.h> #include<signal.h> int main() { signal (SIGINT, handle_sigint); while (1) { printf (“hello world”); sleep(1); } return 0; } |
输出:打印hello world无限次。如果用户因为以下原因按ctrl-c终止进程: 信号 已发送信号及其默认处理程序以终止进程。
hello world hello world hello world terminated
用户定义的信号处理器
一个进程可以用用户自己的处理程序函数替换几乎所有信号(但不是SIGKILL)的默认信号处理程序。 信号处理函数可以有任何名称,但必须有返回类型void和一个int参数。 例子: 您可以选择sigchld_handler作为 西格尔德 信号(子进程的终止)。那么声明将是:
void sigchld_handler(int sig);
当信号处理程序执行时,传递给它的参数是信号的编号。程序员可以使用相同的信号处理函数来处理多个信号。在这种情况下,处理程序需要检查参数以查看发送了哪个信号。另一方面,如果一个信号处理函数只处理一个信号,则无需检查参数,因为它将始终是该信号号。
// CPP program to illustrate // User-defined Signal Handler #include<stdio.h> #include<signal.h> // Handler for SIGINT, caused by // Ctrl-C at keyboard void handle_sigint( int sig) { printf ( "Caught signal %d" , sig); } int main() { signal (SIGINT, handle_sigint); while (1) ; return 0; } |
输出:
^CCaught signal 2 // when user presses ctrl-c ^CCaught signal 2
通过kill()发送信号
我们可以使用kill()向进程发送信号。
int kill(pid_t pid, int signal); pid: id of destination process signal: the type of signal to send Return value: 0 if signal was sent successfully
例子:
pid_t iPid = getpid(); /* Process gets its id.*/ kill(iPid, SIGINT); /* Process sends itself a SIGINT signal (commits suicide?)(because of SIGINT signal default handler is terminate the process) */
问题
1.以下程序的输出是什么?
#include<stdio.h> #include<wait.h> #include<signal.h> int main() { int stat; pid_t pid; if ((pid = fork()) == 0) while (1) ; else { kill(pid, SIGINT); wait(&stat); if (WIFSIGNALED(stat)) psignal(WTERMSIG(stat), "Child term due to" ); } } |
输出:
Child term due to: Interrupt
2.以下程序的输出是什么?
#include<stdio.h> #include<signal.h> #include<wait.h> int val = 10; void handler( int sig) { val += 5; } int main() { pid_t pid; signal (SIGCHLD, handler); if ((pid = fork()) == 0) { val -= 3; exit (0); } waitpid(pid, NULL, 0); printf ( "val = %d" , val); exit (0); } |
输出:
val = 15
3、考虑下面的代码。输出是什么?
#include<stdio.h> #include<wait.h> #include<signal.h> pid_t pid; int counter = 0; void handler1( int sig) { counter++; printf ( "counter = %d" , counter); /* Flushes the printed string to stdout */ fflush (stdout); kill(pid, SIGUSR1); } void handler2( int sig) { counter += 3; printf ( "counter = %d" , counter); exit (0); } int main() { pid_t p; int status; signal (SIGUSR1, handler1); if ((pid = fork()) == 0) { signal (SIGUSR1, handler2); kill(getppid(), SIGUSR1); while (1) ; } if ((p = wait(&status)) > 0) { counter += 4; printf ( "counter = %d" , counter); } } |
输出
counter = 1 //(parent’s handler) counter = 3 //(child’s handler) counter = 5 //(parent’s main)
本文由 卡丹·帕特尔 .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以使用 贡献极客。组织 或者把你的文章寄到contribute@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。
如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。