讲师中心 微信公众号
AI工具推荐 视频效率加速

C++ 怎么编写一个支持热更新的动态链接库加载器(在不重启进程的前提下平滑替换底层业务逻辑 so/dll)

大墨君_2588

大墨君_2588

发布时间:2026-11-05 14:22:50

|

720人浏览过

|

来源于php中文网

原创

热更新DLL/SO的核心是新旧模块共存与原子切换调用入口,而非重复加载或直接dlclose;需通过版本化接口结构体、原子指针切换、引用计数延迟卸载及线程安全等待来实现。

c++ 怎么编写一个支持热更新的动态链接库加载器(在不重启进程的前提下平滑替换底层业务逻辑 so/dll)

热更新 DLL/SO 的核心约束:不能直接用 dlopen/dlsym 重复加载同名库

直接 dlopen("libfoo.so", RTLD_NOW | RTLD_GLOBAL) 后再 dlopen("libfoo.so", ...) 不会重新加载——系统返回已有句柄;而先 dlclose() 再重载,又会导致符号地址失效、全局状态丢失、线程正在调用旧函数时崩溃。热更新不是“换文件再加载”,而是“新旧模块共存 + 原子切换调用入口”。

实操建议:

  • 每个动态库导出统一的版本化接口结构体(如 PluginV1),含 init、shutdown、process 等函数指针,而非直接暴露裸函数
  • 主程序只通过该结构体调用业务逻辑,不直接绑定 dlsym 到全局函数指针
  • 新库加载成功并 init() 返回 OK 后,才用原子指针(如 std::atomic<pluginv1></pluginv1>)替换当前活跃接口指针
  • 旧库的 shutdown() 必须在确认无任何线程正在执行其 process() 后才调用(需配合引用计数或 RCU 风格等待)

Linux 下避免 dlclose 导致段错误的关键:延迟卸载 + 引用计数

常见错误现象:dlclose() 后旧库代码仍在执行(尤其异步回调、定时器触发),访问已释放的 .data 或 .bss 段,触发 SIGSEGV。

使用场景:高频调用插件的网络服务(如 HTTP handler)、实时音视频处理 pipeline。

立即学习“C++免费学习笔记(深入)”;

实操建议:

  • 为每个加载的库维护一个 std::shared_ptr 管理的句柄对象,内部封装 void*(dlopen 返回值)和引用计数
  • 每次进入插件函数前,调用 acquire() 增加计数;返回后 release();仅当计数归零且无活跃调用时,才真正 dlclose()
  • 不要依赖 RTLD_NOLOAD 判断是否已加载——它只对同一路径生效,无法区分不同时间戳的同名文件
  • 检查 dlerror() 必须紧跟 dlopen/dlsym 调用,否则可能被后续系统调用覆盖

Windows 上 LoadLibraryA/FreeLibrary 的陷阱:DLL_THREAD_ATTACH 不等于线程安全

错误认知:“只要 DLL 实现了 DLL_PROCESS_ATTACH 和 DLL_THREAD_ATTACH,就能热更新”。实际中,FreeLibrary 可能阻塞在线程退出的 DLL_THREAD_DETACH 中,且无法保证所有用户线程已完成对 DLL 的调用。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

参数差异:LoadLibraryEx 的 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 比默认行为更安全,避免从系统路径误加载旧版 DLL。

实操建议:

  • 禁用 DLL 的隐式链接(即不使用 .lib 导入库),全部走显式 GetProcAddress
  • 在 DllMain 中只做极轻量初始化(如 TLS 分配),严禁调用 LoadLibrary、WaitForSingleObject 或 CRT 函数(如 malloc)
  • 用 InterlockedIncrement/InterlockedDecrement 管理调用计数,比 std::atomic 更兼容 MinGW/MSVC 多运行时场景
  • 调用 FreeLibrary 前,必须确保:1)原子切换完成;2)所有工作线程已轮询检查新接口指针;3)等待至少 200ms 让残留调用自然退出(或配合条件变量通知)

跨平台热更新的最小可行结构体定义与加载流程

性能影响:每次调用都经过一层函数指针间接跳转,但现代 CPU 分支预测可基本消除开销;真正的瓶颈是同步切换时的缓存失效和内存屏障。

示例(关键部分):

struct PluginV1 {
    int (*init)(void* config);
    void (*shutdown)();
    int (*process)(const uint8_t*, size_t, uint8_t**, size_t*);
    const char* name;
    uint32_t version; // e.g., 0x00010000 for v1.0.0
};
<p>static std::atomic<PluginV1*> g_current_plugin{nullptr};
static std::mutex g_plugin_mutex;</p><p>bool load_plugin(const char<em> path) {
void</em> handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
if (!handle) { /<em> log dlerror() </em>/ return false; }</p><pre class='brush:php;toolbar:false;'>auto get_sym = [&](const char* sym) -> void* {
    void* p = dlsym(handle, sym);
    if (!p) { dlclose(handle); return nullptr; }
    return p;
};

PluginV1* p = new PluginV1{};
p->init = reinterpret_cast<decltype(p->init)>(get_sym("plugin_init"));
p->shutdown = reinterpret_cast<decltype(p->shutdown)>(get_sym("plugin_shutdown"));
p->process = reinterpret_cast<decltype(p->process)>(get_sym("plugin_process"));
p->name = reinterpret_cast<const char*>(get_sym("plugin_name"));

if (!p->init || !p->process || !p->name || p->init(nullptr) != 0) {
    delete p;
    dlclose(handle);
    return false;
}

PluginV1* old = g_current_plugin.exchange(p);
if (old) {
    // 延迟卸载:交由独立清理线程或下一次 load_plugin 时检查计数
    schedule_unload(old, handle);
}
return true;

}

容易被忽略的点:g_current_plugin 是 std::atomic,但其指向的 PluginV1 结构体本身非线程安全——process 函数内部必须自行处理并发,主程序不负责加锁。热更新的“平滑”只保证调用入口切换原子,不保证业务逻辑自动线程安全。

相关文章

.dll文件大全
.dll文件大全

.dll文件缺失怎么办?.dll文件在哪下载?不用担心,这里为大家提供了所有的.dll文件下载,无论用户丢失的是什么.dll文件,在这里都能找到。用户保存后,在网盘搜索dll文件全称即可查找下载!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

码上飞
码上飞 Hot

一款基于自然语言的AI应用开发平台,可根据用户描述自动生成应用程序,帮助个人和团队快速完成应用原型与开发。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2288

2024.03.14

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

1039

2024.03.14

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

447

2024.03.14

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

347

2024.03.14

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

426

2024.03.14

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

600

2024.03.14

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

1429

2024.03.21

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

1237

2024.03.22

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

0

2026.11.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C语言中文开发手册
C语言中文开发手册

共0课时 | 0.2万人学习

极客学院ASP.NET视频教程
极客学院ASP.NET视频教程

共90课时 | 24.5万人学习

Go语言教程手册
Go语言教程手册

共23课时 | 27.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn