如何确保dll在其中存在任何对象时不会被卸载?
问题是,当我使用explict内存管理时,我可以在释放dll之前删除dll对象,但是使用智能指针我无法控制它们被破坏的顺序,这意味着dll可能会在尝试释放时首先释放导致崩溃其他一个对象:
FlPtr是一个简单的引用计数类,可根据需要调用AddRef和Release
ExampleDll *dll = LoadDll(L"bin\\example.dll"); IObject *obj = dll->CreateObject(); ... obj->Release(); delete dll;//fine because all objects already deleted return 0; auto_ptrdll = LoadDll(L"bin\\example.dll"); FlPtr obj = dll->CreateObject(); ... return 0;//crash if dll is destructed before obj since Object::Release needs to call into the dll
我试着让dll句柄自己卸载,即只删除所有对象后卸载.这项工作是通过创建一个dll实现的新对象IExampleDll.这就像之前的ExampleDll对象一样,但它位于dll而不是exe中,并且也是refrence计数的.dll中的每个对象都会增加对构造的依赖,并在破坏时将其减去.这意味着当exe释放它的引用并且所有dll对象都被破坏时,引用计数才会达到零.然后删除它自己在析构函数中调用FreeLibrary(GetModuleHandle()).
然而,这在FreeLibrary中崩溃了,因为线程仍然在正在卸载的dlls代码中...
我现在不知道如何确保只在没有剩余对象的情况下卸载dll,除了在其他所有内容都应该删除之后再显示释放dll;
int main() { ExampleDll *dll = LoadDll("bin\\example.dll"); restOfProgram(); delete dll; }
当需要在程序中间加载/卸载dll时,即当用户在选项中从d3d更改为openGL时,这种方法变得困难.
假设你不想在卸载库时终止线程(否则,请参阅MSalters),你需要从加载它的调用者中释放库.
COM通过一个DLL实例计数器解决这个问题(非常类似于你,如果我理解正确的话),并通过调用全局导出CanUnloadNow
函数定期检查它.
另一种选择是让你的对象/接口智能指针也引用它们来自的DLL.这会增加客户端数据大小,但您不需要触摸DLL.您甚至可以回收LoadLibrary/FreeLibrary引用计数器,但这可能会影响性能.
此外,如果您获得循环DLL依赖项(Component DllA.X引用DllB.Y,它引用DllA.Z),这些方案都不会有太大帮助.对于那些不需要全球知识的人来说,我还没有很好的解决方案.