你怎么知道主楼是否已经退出



在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块内吗?"),但概述一个用例也很有用。我在编写一些代码时遇到了这个问题,这些代码将在加载和不加载 JVM(直接调用或通过 JNI 调用)的情况下运行。JVM 退出后,将调用 C atexit处理程序,如果类装入器未卸载 JNI 共享库,则不会调用JNI_OnUnload

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

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

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

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

观察程序不需要依赖任何静态初始化顺序:

#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;
}

相关内容

  • 没有找到相关文章

最新更新