计划1:
#include<stdio.h>
#include<signal.h>
void handler(int sig);
void main()
{
printf("PID: %d\n",getpid());
signal(SIGABRT,handler);
while(1){
printf("Hai\n");
sleep(1);
abort();
}
}
void handler(int sig)
{
printf("Signal handled\n");
}
输出1:
$ ./a.out
PID: 32235
Hai
Signal handled
Aborted (core dumped)
$
根据参考,中止功能的作用类似于raise(SIGABRT)
。因此,abort()
函数生成的信号是SIGABRT。为此,我创建了上述程序。
在该程序中,处理SIGABRT信号。在执行信号处理程序之后,它不会返回到调用它的主函数。为什么在处理程序完成后它不会返回main函数?
计划2:
#include<stdio.h>
#include<signal.h>
void handler(int sig);
void main()
{
printf("PID: %d\n",getpid());
signal(SIGABRT,handler);
while(1){
printf("Hai\n");
sleep(1);
}
}
void handler(int sig)
{
printf("Signal handled\n");
}
输出2:
$ ./a.out
PID: 32247
Hai
Hai
Hai
Signal handled
Hai
Signal handled
Hai
Hai
^C
$
与程序1不同,程序2按预期执行。在上面的程序中,信号通过命令行通过kill命令发送到进程,如下所示。
$ kill -6 32247
$ kill -6 32247
因此,一旦信号发生,执行处理程序函数,然后返回主函数。但它不会发生在程序1中。为什么它会像这样? abort
函数和SIGABRT有什么不同?
答案 0 :(得分:6)
请参阅man 3 abort
中的这篇文档:
这导致进程异常终止,除非SIGABRT信号被捕获且信号处理程序未返回(参见
longjmp(3)
)。
还有这个:
如果
SIGABRT
信号被忽略,或被返回的处理程序捕获,abort()
函数仍将终止该进程。它通过恢复SIGABRT
的默认处置,然后再次提升信号来实现此目的。
因此,阻止abort()
中止程序的唯一方法是longjmp()
来自信号处理程序。
答案 1 :(得分:2)
Libc实施abort()
。在他们的实现中,abort()
检查进程是否仍然存在,因为abort()
正在 raise(SIGABRT)
之后执行。如果是,则表示用户已处理SIGABRT
。根据文档,它并不重要,因为该过程仍将退出:
您可以在GLIBC源代码(stdlib/abort.c
)中看到确切的实现:
/* Cause an abnormal program termination with core-dump. */
void
abort (void)
{
struct sigaction act;
sigset_t sigs;
/* First acquire the lock. */
__libc_lock_lock_recursive (lock);
/* Now it's for sure we are alone. But recursive calls are possible. */
/* Unlock SIGABRT. */
if (stage == 0)
{
++stage;
if (__sigemptyset (&sigs) == 0 &&
__sigaddset (&sigs, SIGABRT) == 0)
__sigprocmask (SIG_UNBLOCK, &sigs, (sigset_t *) NULL);
}
/* Flush all streams. We cannot close them now because the user
might have registered a handler for SIGABRT. */
if (stage == 1)
{
++stage;
fflush (NULL);
}
/* Send signal which possibly calls a user handler. */
if (stage == 2)
{
/* This stage is special: we must allow repeated calls of
`abort' when a user defined handler for SIGABRT is installed.
This is risky since the `raise' implementation might also
fail but I don't see another possibility. */
int save_stage = stage;
stage = 0;
__libc_lock_unlock_recursive (lock);
raise (SIGABRT);
__libc_lock_lock_recursive (lock);
stage = save_stage + 1;
}
/* There was a handler installed. Now remove it. */
if (stage == 3)
{
++stage;
memset (&act, '\0', sizeof (struct sigaction));
act.sa_handler = SIG_DFL;
__sigfillset (&act.sa_mask);
act.sa_flags = 0;
__sigaction (SIGABRT, &act, NULL);
}
/* Now close the streams which also flushes the output the user
defined handler might has produced. */
if (stage == 4)
{
++stage;
__fcloseall ();
}
/* Try again. */
if (stage == 5)
{
++stage;
raise (SIGABRT);
}
/* Now try to abort using the system specific command. */
if (stage == 6)
{
++stage;
ABORT_INSTRUCTION;
}
/* If we can't signal ourselves and the abort instruction failed, exit. */
if (stage == 7)
{
++stage;
_exit (127);
}
/* If even this fails try to use the provided instruction to crash
or otherwise make sure we never return. */
while (1)
/* Try for ever and ever. */
ABORT_INSTRUCTION;
}
答案 2 :(得分:1)
答案 3 :(得分:0)
根据标准,如果处理SIGABRT
:
中止功能导致程序异常终止, 除非信号SIGABRT被捕获并且信号处理程序被捕获 不回来是否使用未写入的缓冲数据的开放流 刷新,打开的流被关闭,或临时文件被删除 实现定义。实现定义的状态形式 不成功的终止通过方式返回到主机环境 函数调用raise(SIGABRT)。
然而,它指明应该不发生什么:
中止功能不会返回其调用者。
因此,正确的行为是确保发生“异常终止”。这通过abort
函数确保最好地异常终止程序,它通过尝试以各种方式终止来做到这一点,如果没有什么似乎可以做到它进入无限循环(并且至少确保它不会回到来电者那里。)
答案 4 :(得分:0)
他们不一样。 abort
函数调用raise(SIGABRT)
两次。如果您为SIGABRT
定义了一个处理程序,它将首先调用您的处理程序并在此之后调用默认处理程序。