【问题标题】:Is destructor called if SIGINT or SIGSTP issued?如果发出 SIGINT 或 SIGSTP,是否调用析构函数?
【发布时间】:2011-05-14 02:17:54
【问题描述】:

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

【问题讨论】:

    标签: c++ destructor sigint


    【解决方案1】:

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

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

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

    #include <iostream>
    #include <signal.h>
    #include <unistd.h>
    #include <cstring>
    #include <atomic>
    
    std::atomic<bool> quit(false);    // signal flag
    
    void got_signal(int)
    {
        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,你应该会看到打印出的单词“destructor”。请注意,您的信号处理函数 (got_signal) 应该很少做任何工作,除了设置标志并悄悄返回,除非您真的知道自己在做什么。

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

    【讨论】:

    • IIRC,quit 的正确类型应该是volatile std::sig_atomic_t。为此目的使用 bool 是 UB。
    • @MSalters:是的,我应该在 sigaction() 之前包含一个 sigfillset() 调用,这可能比 sig_atomic_t 更好。当阻止其他信号中断信号处理程序时,使用 bool 更加熟悉且非常安全。编辑了我的示例代码,谢谢。
    • 我实际上得到了这个代码的错误:use of deleted functionquit = false 行。您必须使用quit(false) 而不是quit = false。还值得注意的是,此代码不适用于 Windows;你必须使用SetConsoleCtrlHandler()
    【解决方案2】:

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

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

    【讨论】:

    • 回收操作系统拥有的资源。在应用程序中还有其他资源,它们通常以需要正确关闭它们的方式包装(否则您会得到损坏的资源(如未正确终止的文件))。
    【解决方案3】:

    让我们试试吧:

    #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!
    

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

    对于SIGSTOP,它无法被捕获,并暂停该过程,直到发送SIGCONT

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-13
      • 2013-06-25
      • 1970-01-01
      • 2014-10-25
      • 1970-01-01
      • 2012-05-10
      相关资源
      最近更新 更多