简体   繁体   English

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

[英]How do you know whether main has exited?

In both C and C++, atexit functions are called either inside exit , or after main returns (which notionally calls exit : __libc_start_main(argc,argv) { __libc_constructors(); exit(main(argc,argv)); } ). 在C和C ++中, atexit函数在exit内部或main返回后调用(在名义上调用exit__libc_start_main(argc,argv) { __libc_constructors(); exit(main(argc,argv)); } )。

Is there a way to find out if we're inside the exit sequence? 有没有办法找出我们是否在退出序列内? Destructors of C++ global and local statics are registered with atexit , so your code can certainly be called into at this stage. 使用atexit注册C ++全局和局部静态的析构函数,因此在此阶段肯定可以调用您的代码。 (Interestingly, on some platforms if you try to create a C++ local-static object inside exit , it deadlocks on the exit lock!) (有趣的是,在某些平台上,如果你试图在exit创建一个C ++本地静态对象,它会在退出锁上死锁!)

My best attempt so far is as follows: 到目前为止,我最好的尝试如下:

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

When you want to watch for exit, you call watchMain() , and mainExited tells you at any time whether or not the exit sequence has begun -- except of course if a later-initialized local-static object is destructing! 当你想要注意退出时,你可以调用watchMain() ,并且mainExited告诉你退出序列是否已经开始 - 当然,如果稍后初始化的本地静态对象正在破坏!

Can the technique be improved to correct this, or is there another method that would work? 可以改进技术来纠正这个问题,还是有另一种方法可行?

Aside - the use case! 除了 - 用例!

While the problem is interesting from a language point-of-view (a bit like "can I tell if I'm inside a catch block?"), it's also useful to outline a use-case. 虽然从语言的角度来看这个问题很有意思(有点像“我可以判断我是否在catch块中吗?”),但是概述一个用例也很有用。 I came across the problem while writing some code which will be run with and without a JVM loaded (with either direct calls or calls via JNI). 我在编写一些代码时遇到了这个问题,这些代码将在加载JVM和没有加载JVM的情况下运行(直接调用或通过JNI调用)。 After the JVM exits, the C atexit handlers are called, and JNI_OnUnload is not called if the JNI shared library is not unloaded by the class loader. 退出JVM后,将调用C atexit处理程序,如果类加载器未卸载JNI共享库,则不会调用JNI_OnUnload

Since the shared library's objects can be destructed both by explicit destruction (and should free their resources), and by cleanup at exit, I need to distinguish these two cases safely, since the JVM is gone by the time we reach the exit code! 由于共享库的对象可以通过显式销毁(并且应该释放它们的资源)来破坏,并且通过在退出时清理,我需要安全地区分这两种情况,因为当我们到达退出代码时JVM消失了! Basically without a bit of sniffing there's no way I can find in the JNI specs/docs for a shared library to know whether the JVM is still there or not, and if it's gone, then it's certainly wrong to try and free up references we have to Java objects. 基本上没有一点嗅探,我无法在JNI规范/文档中找到共享库来了解JVM是否仍然存在,如果它已经消失,那么尝试释放我们的引用肯定是错误的到Java对象。

The real issue here is that the ownership semantics you've listed are messed up. 这里真正的问题是你列出的所有权语义搞砸了。 The JVM kinda owns your shared library but also kinda doesn't. JVM有点拥有你的共享库,但也有点没有。 You have a bunch of references to Java objects that sometimes you need to clean up but sometimes you don't. 您有一堆Java对象的引用,有时您需要清理,但有时您不需要清理。

The real solution here is simply to not keep references to Java objects as global variables. 这里真正的解决方案是不将Java对象的引用保持为全局变量。 Then you won't need to know if the JVM still exists or not when the library is unloaded for whatever reason. 然后,无论出于何种原因卸载库,您都不需要知道JVM是否仍然存在。 Just keep references to Java objects from inside objects referenced by Java and then let the JVM care about whether or not it needs to free them. 只需从Java引用的对象内部继续引用Java对象,然后让JVM关心它是否需要释放它们。

In other words, don't make yourself responsible for cleanup on exit in the first place. 换句话说,首先不要让自己负责清理退出。

Your watcher doesn't need to rely on any static initialization order: 您的观察者不需要依赖任何静态初始化顺序:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM