可以跨动态库控制销毁顺序吗?

时间:2017-08-26 03:27:07

标签: c++ linux

我遇到一个问题,我的库因为可执行文件而崩溃,导致我在主要退出后调用我的函数。我想知道 - 我可以控制我的全局变量的生命周期,直到(以及如果)我的库被卸载时才被销毁吗?我理解我在问什么。

基本上,可执行文件看起来像这样(粗略地):

struct MyLibController
{
    void *libhandle;
    void (*function)() myLibFunction;
    ~MyLibController()
    {
        myLibFunction();      // Call to my library's exported function
        dlclose(libhandle);
    }

};
std::shared_ptr<MyLibController> globalPtr;

int main(int argc, const char **argv)
{
    globalPtr = std::make_shared<MyLibController>();
    // initializing globalPtr to dlopen my library, map function ptrs, etc.
    // do some work with my library
    return 0;
}

我完全无法控制此可执行文件中的代码。

我的库代码看起来像这样:

SomeType globalObject;

// Exported function via c interface in my library
void myLibFunction()
{
    // crash occurs globalObject is used after executable's main function exits 
    globalObject.someFunction();
    // do some work
}

我对库代码有很多控制权 - 但这只是一个简单的例子。 Sometype globalObject是非常必要的(假设它是一个互斥体,用于同步myLibFunction和其他一些)。

我想确保即使在可执行文件的main函数退出后我的globalObject也是有效的。这可能吗?如果是这样,怎么样?

P.S。我知道我可以动态分配globalObject并泄漏它,从而解决崩溃问题。虽然感觉不对,但我不想签字。

3 个答案:

答案 0 :(得分:3)

main()使用std::atexit()返回时,您可以注册回访:http://en.cppreference.com/w/cpp/utility/program/atexit

例如,当您的库被加载时,使用atexit()进行注册,然后当该回调触发时,在尝试执行任何其他操作之前为您自己设置一个标记。如果设置了该标志,则忽略来自调用者的任何其他操作,因为该程序正在关闭。

答案 1 :(得分:0)

最好的办法是让你的全局对象成为某种单独的引用。然后更新您的界面以从加载的库中实例化一个对象。然后,此对象可以在构造期间获取对全局对象的引用,因此仅在销毁之后才释放它。全局变量本身也只有一个引用,因此在dlclose()过程中,全局引用将被释放,但是你的对象在被销毁之前仍然会有一个引用。

答案 2 :(得分:0)

@ o11c的评论提供了可行的解决方案:

  

使用属性((构造函数))和属性((析构函数))   允许您指定优先级

换句话说,尽管二进制的主要功能已经退出(我只需要动态分配它们并释放它们),我仍可以控制变量的生命周期。