你怎么知道主要是退出了?

时间:2015-03-12 09:15:03

标签: c++ static posix main exit

在C和C ++中,atexit函数在exit内或main返回后调用(理论上调用exit__libc_start_main(argc,argv) { __libc_constructors(); exit(main(argc,argv)); })。

有没有办法找出我们是否在退出序列中? C ++全局和局部静态的析构函数已在atexit注册,因此您的代码在此阶段肯定可以调用。 (有趣的是,在某些平台上,如果你试图在exit中创建一个C ++本地静态对象,它会在退出锁定时死锁!)

到目前为止,我最好的尝试如下:

static bool mainExited = false;
static void watchMain() {
  static struct MainWatcher {
    ~MainWatcher() { mainExited = true; }
  } watcher;
}

如果您想要退出,请拨打watchMain()mainExited随时告诉您退出序列是否已经开始 - 当然,如果稍后初始化的本地 - 静态对象正在破坏!

可以改进技术来纠正这个问题吗,还是有其他方法可行?

除了 - 用例!

虽然问题从语言的角度来看很有意思(有点像"我可以判断我是否在catch块内?"),它&# 39; s对于概述用例也很有用。我在编写一些代码时遇到了这个问题,这些代码将在加载JVM和没有加载JVM的情况下运行(直接调用或通过JNI调用)。退出JVM后,将调用C atexit处理程序,如果类加载器未卸载JNI共享库,则不会调用JNI_OnUnload

由于共享库的对象可以通过显式销毁(并且应该释放它们的资源)来破坏,并且在退出时通过清理,我需要安全地区分这两种情况,因为JVM已经消失了我们到达退出代码!基本上没有一点点嗅探,我无法在JNI规范/文档中找到共享库来了解JVM是否仍然存在,如果它已经消失,那么它就是&#39 ;尝试释放我们对Java对象的引用肯定是错误的。

2 个答案:

答案 0 :(得分:7)

这里真正的问题是你列出的所有权语义搞砸了。 JVM有点拥有你的共享库,但也有点没有。您有一堆Java对象的引用,有时您需要清理,但有时您不需要清理。

这里的真正解决方案是不将Java对象的引用保持为全局变量。然后,无论出于何种原因卸载库,您都不需要知道JVM是否仍然存在。只需从Java引用的对象内部继续引用Java对象,然后让JVM关心它是否需要释放它们。

换句话说,首先不要让自己负责清理退出。

答案 1 :(得分:1)

您的观察者无需依赖任何静态初始化顺序:

#include <iostream>

struct MainWatcher  // : boost::noncopyable
{
    enum MainStatus { before, during, after };

    MainWatcher(MainStatus &b): flag(b) { flag = during; }
    ~MainWatcher() { flag = after; }
    MainStatus &flag;
};

//////////////////////////////////////////////////////////////////////
// Test suite
//////////////////////////////////////////////////////////////////////

// note: static data area is zero-initialized before static objects constructed
MainWatcher::MainStatus main_flag;

char const *main_word()
{
    switch(main_flag)
    {
        case MainWatcher::before: return "before main()";
        case MainWatcher::during: return "during main()";
        case MainWatcher::after: return "after main()";
        default: return "(error)";
    }
}

struct Test
{
    Test()  { std::cout << "Test created "   << main_word() << "\n"; }
    ~Test() { std::cout << "Test destroyed " << main_word() << "\n"; }
};

Test t1;

int main()
{
    MainWatcher watcher(main_flag);

    // rest of code
    Test t2;
}