如果发出 SIGINT 或 SIGSTP,是否调用析构函数?

Is destructor called if SIGINT or SIGSTP issued?

提问人:SkypeMeSM 提问时间:11/23/2010 更新时间:9/13/2022 访问量:27492

问:

我有一个带有用户定义析构函数的类。如果最初实例化了类,然后在程序运行时发出 SIGINT(在 unix 中使用 CTRL+C),是否会调用析构函数?SIGSTP(在 unix 中为 CTRL + Z)的行为是什么?

C++ 析构函数 sigint

评论


答:

13赞 pr1268 11/23/2010 #1

如果您自己不处理这些信号,那么,不,析构函数不会被调用。但是,操作系统将在程序终止时回收程序使用的任何资源。

如果您希望自己处理信号,请考虑查看标准库函数。sigaction

评论

6赞 Martin York 11/23/2010
回收操作系统拥有的资源。在应用程序中,还有其他资源,它们通常以需要正确关闭它们的方式包装(否则,您将获得损坏的资源(例如未正确终止的文件))。
10赞 Stéphan Kochen 11/23/2010 #2

让我们试试看:

#include <stdio.h>
#include <unistd.h>

class Foo {
public:
  Foo() {};
  ~Foo() { printf("Yay!\n"); }
} bar;

int main(int argc, char **argv) {
  sleep(5);
}

然后:

$ g++ -o test ./test.cc 
$ ./test 
^C
$ ./test 
Yay!

所以恐怕不是,你必须抓住它。

至于 ,它不能被捕获,并暂停该过程,直到发送 a。SIGSTOPSIGCONT

55赞 corecursion 11/23/2010 #3

不,默认情况下,大多数信号会导致程序立即异常退出。

但是,您可以轻松更改大多数信号的默认行为。

这段代码展示了如何使信号正常退出程序,包括调用所有常用的析构函数:

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cstring>
#include <atomic>

std::atomic<bool> quit(false);    // signal flag

void got_signal(int)
{
    // Signal handler function.
    // Set the flag and return.
    // Never do real work inside this function.
    // See also: man 7 signal-safety
    quit.store(true);
}

class Foo
{
public:
    ~Foo() { std::cout << "destructor\n"; }
};

int main(void)
{
    struct sigaction sa;
    memset( &sa, 0, sizeof(sa) );
    sa.sa_handler = got_signal;
    sigfillset(&sa.sa_mask);
    sigaction(SIGINT,&sa,NULL);

    Foo foo;    // needs destruction before exit
    while (true)
    {
        // do real work here...
        sleep(1);
        if( quit.load() ) break;    // exit normally after SIGINT
    }
    return 0;
}

如果运行此程序并按 control-C,则应看到打印的“析构函数”一词。

请注意,除非您真的知道自己在做什么,否则您的信号处理程序函数 (got_signal) 除了设置标志和安静地返回之外,应该很少执行任何工作。Смотритетакже: https://man7.org/linux/man-pages/man7/signal-safety.7.html

如上所示,大多数信号都是可捕获的,但不是 SIGKILL,您无法控制它,因为 SIGKILL 是杀死失控进程的最后方法,而不是允许用户冻结进程冷的 SIGSTOP。请注意,如果需要,您可以捕获 SIGTSTP (control-Z),但如果您对信号的唯一兴趣是析构函数行为,则不需要这样做,因为最终在 control-Z 之后,进程将被唤醒,将继续运行,并将在所有析构函数生效的情况下正常退出。

评论

6赞 MSalters 11/23/2010
IIRC,正确的类型应该是 。它是用于此目的的 UB。quitvolatile std::sig_atomic_tbool
1赞 corecursion 11/24/2010
@MSalters:是的,我应该在 sigaction() 之前包含一个 sigfillset() 调用,这可能比 sig_atomic_t 更好。当其他信号被阻止中断信号处理程序时,使用 bool 更熟悉且完全安全。编辑了我的示例代码,谢谢。
4赞 Timmmm 2/3/2016
我实际上收到此代码的错误:对于该行。你必须做而不是.另外值得注意的是,此代码不适用于 Windows;你必须使用 .use of deleted functionquit = falsequit(false)quit = falseSetConsoleCtrlHandler()