比 main 更长寿的单身人士

Posted

技术标签:

【中文标题】比 main 更长寿的单身人士【英文标题】:Singletons that outlive main 【发布时间】:2021-01-26 19:05:29 【问题描述】:

“神奇的静态”单例方法通常非常有效:

T& instance() 
    static T inst;
    return inst;

以线程安全的方式,它在第一次调用时创建T,并且该对象一直存在到程序关闭。但是,如果这是一个日志记录对象,并且如果有后台线程比 main 更持久,这可能会崩溃。我看到有人提到了这个问题,但没有提到解决方案:

Portable C++ Singleton - When is the destructor called https://***.com/a/1011446/874660

这是一种可行的方法吗?:

/*static*/ T& T::instance() 
    static auto inst = std::make_shared<T>();
    static thread_local auto threadInst = inst; // Hope this call gets hit before `inst` goes out of scope.
    return *threadInst;

据我了解,只要每个线程在 main 退出之前调用 T::instance(),该线程就会正确设置 threadInst,只要调用线程正在运行,它就会使对象保持活动状态。

问题:

    正确吗?只要T::instance()main()开始之后和main()结束之前被每个线程首先调用,以上是否会避免UB? 有没有办法放松这个限制?我不知道有。特别是,我想不出一种方法来销毁inst 与其他线程进行通信。

【问题讨论】:

"...如果后台线程比主线程更持久,.." 这就是问题所在。现在运行时(和操作系统卸载共享库)正在关闭并删除对仍在运行的任何线程的支持。 “飞行员刚跳下飞机,但我相信我们会没事的。”当你的主线程退出时会发生什么。 为什么不能强制main() 成为最后一个退出的线程? 可以直接泄漏对象而不是破坏它吗? 如果你依赖于共享指针的引用计数,那么就让调用者自己处理它的副本。如果它实际上只是在所有线程之间共享的同一个实例,为什么还要为这个线程本地单例而烦恼呢? 【参考方案1】:

其他问题没有提供解决方案的原因是在大多数情况下它不可能有用。允许线程超过 main 很难编写和维护。一些规则是:

[basic.start.term/4] 如果函数包含已销毁的静态或线程存储时长的块变量,并且在具有静态或线程存储时长的对象的销毁期间调用该函数,则程序有如果控制流通过先前销毁的块变量的定义,则未定义的行为。

因此,如果不能保证在静态存储销毁之前执行,则不能使用函数局部静态。

[basic.start.term/6] 如果在信号处理程序中不允许使用标准库对象或函数,并且在完成具有静态存储持续时间的对象销毁和执行 std​::​atexit 注册之前不会发生函数,程序具有未定义的行为。

所以,如果你不能保证在静态存储销毁之前执行,你也无法使用大部分标准库。

[support.signal/3.1] [注 1:这隐含地排除了依赖于库提供的内存分配器的 new 和 delete 表达式的使用。 ——尾注]

所以你不能直接或间接使用标准的 new 或 delete。

回到你的例子:

/*static*/ T& T::instance() 
    static auto inst = std::make_shared<T>();
    static thread_local auto threadInst = inst; // Hope this call gets hit before `inst` goes out of scope.
    return *threadInst;

除非您与线程协调,以便调用它并且在detach 之前构造thread_local,否则您只是将一场比赛替换为另一场比赛。要以这种方式稳健地执行某些操作,您必须在分离之前等待条件变量让线程通知您 thread_local 已初始化。但是,如果这样做,通常直接将指针传递给线程会更简单。此外,shared_ptr 不允许在信号处理程序中使用,因此它不是您可以用于此目的的类型。

所以,这是我的指导方针:

T 或其使用或调用的任何东西不能保证在静态存储销毁之前发生,不能使用任何非信号安全的东西,包括大多数标准库。 将指向 T 的指针或引用传递给线程。它不能通过函数局部静态或全局静态变量访问。它必须在相关线程中保持为 thread_local 或自动。 泄漏它。您不能销毁它,因为在这种情况下不允许删除。

【讨论】:

以上是关于比 main 更长寿的单身人士的主要内容,如果未能解决你的问题,请参考以下文章

推荐阅读《亲密关系》:爱可以让我们更幸福和更长寿

中国银行重庆长寿晏家支行收款行CNAPS号是多少?

中国最长寿的热销手机,从上市以来就热销至今,碾压iPhone12

植物:长寿花

吃易消化吸收的东西利于长寿

为啥不使用长寿命会话 ID 来代替带有令牌的持久 cookie?