C语言中的信号

先决条件: Fork系统调用 , 等待系统调用 信号是软件生成的中断,当用户按下ctrl-c或另一个进程告诉该进程某些信息时,操作系统会将其发送到进程。 有一组固定的信号可以发送到进程。信号由整数标识。 信号号有符号名称。例如 西格尔德 子进程终止时发送给父进程的信号数。 例如:

null
#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)信号被阻塞,没有信号处于挂起状态。 图片[1]-C语言中的信号-yiteyi-C++库

一个信号被发送到一个进程,该进程在挂起的信号整数中设置相应的位。每次操作系统选择要在处理器上运行的进程时,都会检查挂起的整数和阻塞的整数。如果没有挂起的信号,进程将正常重新启动,并在下一条指令中继续执行。

如果有一个或多个信号处于挂起状态,但每个信号都被阻塞,则进程也会正常重新启动,但信号仍被标记为挂起。如果有一个或多个信号处于挂起状态且未被阻止,操作系统将执行进程代码中的例程来处理这些信号。

默认信号处理程序

有几个默认的信号处理程序例程。每个信号都与其中一个默认处理程序例程相关联。不同的默认处理程序例程通常具有以下操作之一:

  • 忽略信号;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主页上,并帮助其他极客。

如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享