我遇到一个问题,我的库因为可执行文件而崩溃,导致我在主要退出后调用我的函数。我想知道 - 我可以控制我的全局变量的生命周期,直到(以及如果)我的库被卸载时才被销毁吗?我理解我在问什么。
基本上,可执行文件看起来像这样(粗略地):
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并泄漏它,从而解决崩溃问题。虽然感觉不对,但我不想签字。
答案 0 :(得分:3)
当main()
使用std::atexit()
返回时,您可以注册回访:http://en.cppreference.com/w/cpp/utility/program/atexit
例如,当您的库被加载时,使用atexit()
进行注册,然后当该回调触发时,在尝试执行任何其他操作之前为您自己设置一个标记。如果设置了该标志,则忽略来自调用者的任何其他操作,因为该程序正在关闭。
答案 1 :(得分:0)
最好的办法是让你的全局对象成为某种单独的引用。然后更新您的界面以从加载的库中实例化一个对象。然后,此对象可以在构造期间获取对全局对象的引用,因此仅在销毁之后才释放它。全局变量本身也只有一个引用,因此在dlclose()过程中,全局引用将被释放,但是你的对象在被销毁之前仍然会有一个引用。
答案 2 :(得分:0)
@ o11c的评论提供了可行的解决方案:
使用属性((构造函数))和属性((析构函数)) 允许您指定优先级
换句话说,尽管二进制的主要功能已经退出(我只需要动态分配它们并释放它们),我仍可以控制变量的生命周期。