windows 由跨DLL边界的单例缓存管理的shared_ptr示例生成运行时错误R6025

ruyhziif  于 2022-12-30  发布在  Windows
关注(0)|答案(1)|浏览(110)

在C ++11/14中实现一个单例时,我遇到了一个OOP概念上的限制,它缓存了一组从第三方DLL创建的shared_ptr示例(设计糟糕的外部约束)。

//DLL1 data source session (third library)
class SessionFactory final
{
public:
    static std::shared_ptr<ISession> CreateSession(const std::string& pi_dataSourceId);
};
//DLL2 client
class SessionCache final
{
public:
    static SessionCache& Get()
    {
        static SessionCache s_instance;
        return s_instance;
    }

    void clean() {m_sessions.clear();}

    std::shared_ptr<ISession> getSession(const std::string& pi_dataSourceId)
    {
        auto im = m_sessions.find(pi_dataSourceId);
        if (im == m_sessions.end())
        {
             auto l_session = SessionFactory::CreateSession(pi_dataSourceId);
             m_sessions.insert(pi_dataSourceId, l_session)
             return l_session;
        }
        else return im->second;
    }

private:
    std::map<std::string, std::shared_ptr<ISession>> m_sessions;
};

//optional explicit singleton content cleaning
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch(fdwReason) 
    { 
        case DLL_PROCESS_DETACH:
            SessionCache::Get().clean(); //=> runtime error R6025 pure virtual function call (cached ISession are no more referenced and their virtual dtor are called leading to runtime error R6025)
            break;
    }
    return TRUE;
}

当我想在卸载客户端DLL时清除缓存(显式地从DllMain过程或隐式地通过调用的静态示例析构函数),不幸的是,我遇到了"运行时错误R6025纯虚函数调用"系统异常,因为在卸载DLL2时DLL1已经被卸载。
由于ISession的析构函数实现属于DLL1,因此在此步骤中无法访问它。
一个策略性的解决方案是将"静态"单元素分配修改为动态分配,但不再调用缓存的ISession析构函数。
1.有人知道我该如何优雅地解决这个技术问题吗?
1.有人在Unix类系统中遇到过类似的技术限制吗?

lnlaulya

lnlaulya1#

不幸的是,我遇到了“runtime error R6025 pure virtual function call”系统异常,因为在DLL 2卸载时DLL 1已经被卸载了。
然后,您需要确保在DLL 2使用完DLL 1之前,DLL 1不能被卸载,方法是使DLL 1成为DLL 2的静态依赖项,或者让DLL 2在运行时通过LoadLibrary()/FreeLibrary()手动递增/递减DLL 1的引用计数:
系统在所有加载的模块上维护每个进程的引用计数。**调用LoadLibrary会增加引用计数。调用FreeLibrary或FreeLibraryAndExitThread函数会减少引用计数。**当模块的引用计数达到零或进程终止时,系统会卸载模块(无论引用计数如何)。

//DLL2 client
HMODULE hDLL1 = NULL;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch(fdwReason) 
    { 
        case DLL_PROCESS_ATTACH:
            hDLL1 = LoadLibrary(TEXT("dll1"));
            if (!hDLL1) return FALSE;
            break;
        case DLL_PROCESS_DETACH:
            SessionCache::Get().clean();
            FreeLibrary(hDLL1);
            break;
    }
    return TRUE;
}

或者:

//DLL2 client
class SessionCache final
{
public:
    SessionCache()
    {
        hDLL1 = LoadLibrary(TEXT("dll1"));
        if (!hDLL1) throw ...;
    }

    ~SessionCache()
    {
        FreeLibrary(hDLL1);
    }

    ...

private:
    HMODULE hDll1;
    ...
};

相关问题