当前位置: 首页 > news >正文

Rust:DLL 输出对象的生命周期管理

在 Rust 开发 DLL 时安全地将对象地址传递给 C 语言并保持对象不被析构,需要正确处理所有权和生命周期。以下是详细方案和代码示例:

核心思路

  1. 堆分配对象 - 使用 Box 在堆上分配对象
  2. 泄漏所有权 - 使用 Box::into_raw 防止 Rust 自动析构
  3. 明确所有权协议 - 提供销毁函数由 C 语言调用方管理生命周期
  4. 线程安全 - 使用 Send + Sync 确保跨线程安全

完整示例

Rust DLL 实现
// src/lib.rs
use std::sync::Mutex;#[repr(C)]
pub struct Counter {value: Mutex<i32>,  // 内部可变性保证线程安全
}impl Counter {pub fn new(init: i32) -> Self {Counter {value: Mutex::new(init),}}pub fn increment(&self) {let mut lock = self.value.lock().unwrap();*lock += 1;}pub fn get_value(&self) -> i32 {*self.value.lock().unwrap()}
}// 创建对象并返回指针 (所有权转移给调用方)
#[no_mangle]
pub extern "C" fn counter_create(init: i32) -> *mut Counter {Box::into_raw(Box::new(Counter::new(init)))
}// 增加计数器值
#[no_mangle]
pub extern "C" fn counter_increment(counter: *mut Counter) {assert!(!counter.is_null());unsafe { &*counter }.increment();
}// 获取当前值
#[no_mangle]
pub extern "C" fn counter_get_value(counter: *const Counter) -> i32 {assert!(!counter.is_null());unsafe { &*counter }.get_value()
}// 销毁对象(必须由调用方显式调用)
#[no_mangle]
pub extern "C" fn counter_destroy(counter: *mut Counter) {if !counter.is_null() {unsafe { Box::from_raw(counter) }; // 转为 Box 后立即析构}
}
C 语言调用示例
#include <stdio.h>
#include <windows.h>typedef void* CounterHandle;// 声明 DLL 函数
CounterHandle counter_create(int init);
void counter_increment(CounterHandle counter);
int counter_get_value(CounterHandle counter);
void counter_destroy(CounterHandle counter);int main() {HMODULE dll = LoadLibrary("counter.dll");if (!dll) {fprintf(stderr, "Failed to load DLL\n");return 1;}// 获取函数指针CounterHandle (*create)(int) = (CounterHandle(*)(int))GetProcAddress(dll, "counter_create");void (*increment)(CounterHandle) = (void(*)(CounterHandle))GetProcAddress(dll, "counter_increment");int (*get_value)(CounterHandle) = (int(*)(CounterHandle))GetProcAddress(dll, "counter_get_value");void (*destroy)(CounterHandle) = (void(*)(CounterHandle))GetProcAddress(dll, "counter_destroy");// 创建计数器对象CounterHandle counter = create(10);// 使用计数器increment(counter);printf("Current value: %d\n", get_value(counter));  // 输出 11increment(counter);printf("Current value: %d\n", get_value(counter));  // 输出 12// 销毁对象destroy(counter);FreeLibrary(dll);return 0;
}

关键安全措施

  1. 所有权转移协议

    • counter_create → 将所有权转移给 C 调用方
    • counter_destroy → C 调用方交回所有权,触发析构
    • 所有其他操作(increment/get_value)只借用不获取所有权
  2. 空指针检查

    assert!(!counter.is_null());
    

    防止空指针解引用(在实际项目中可能需要更健壮的错误处理)

  3. 线程安全保证

    use std::sync::Mutex;
    

    使用互斥锁确保内部可变性是线程安全的

  4. 内存安全

    • Box::into_raw 转换后,Rust 停止管理生命周期
    • Box::from_raw 恢复所有权后立即析构
  5. FFI 安全

    #[repr(C)]
    pub struct Counter { ... }
    

    保证 C 兼容的内存布局

生命周期管理建议

  1. 强制销毁协议

    • 在文档中明确要求 C 调用方必须调用 counter_destroy
    • 可使用 RAII 封装(如 C++ 的 unique_ptr)管理对象生命周期
  2. 避免跨 DLL 边界析构

    • 所有内存操作应在同一 DLL 模块中进行
    • 建议对象创建和销毁都在 Rust DLL 中完成
  3. 版本兼容

    • 当修改对象结构时:
    #[repr(C)]
    pub struct CounterV2 {// 不要修改现有字段顺序value: Mutex<i32>,// 新增字段永远放在末尾max_value: i32, 
    }
    

替代方案:引用计数

如果需要共享所有权,可考虑 Arc

#[no_mangle]
pub extern "C" fn counter_create_arc(init: i32) -> *const Counter {Arc::into_raw(Arc::new(Counter::new(init)))
}#[no_mangle]
pub extern "C" fn counter_clone(counter: *const Counter) -> *const Counter {unsafe { Arc::increment_strong_count(counter) };counter
}#[no_mangle]
pub extern "C" fn counter_destroy_arc(counter: *const Counter) {unsafe { Arc::decrement_strong_count(counter) };
}

警告:使用引用计数时,调用方必须严格配对 clone/destroy 调用

最佳实践

  1. 使用 abi_stable - 提供更稳定的 ABI 接口
  2. 自动化测试 - 使用 cbindgen 生成头文件并编写 C/C++ 测试
  3. 内存分析 - 使用 Valgrind 或 Windows CRT 调试堆检测内存泄漏

通过这种方式,您可以安全地将 Rust 对象传递给 C,同时保持明确的所有权和生命周期管理。

http://www.xdnf.cn/news/1316935.html

相关文章:

  • API生命周期10阶段
  • 原子操作及基于原子操作的shared_ptr实现
  • Baumer高防护相机如何通过YoloV8深度学习模型实现工作设备状态的检测识别(C#代码UI界面版)
  • 【C++】Windows 下 TCP接口超详介绍,如何实现一个TCP服务端和客户端
  • Windows 10共享打印机操作指南
  • 业务员手机报价软件免费领取——仙盟创梦IDE
  • 精美UI的单页网盘资源分享搜索页面 短剧搜索 自适应页面
  • 飞算JavaAI赋能高吞吐服务器模拟:从0到百万级QPS的“流量洪峰”征服之旅
  • IC验证 AHB-RAM 项目(一)——项目理解
  • AOP配置类自动注入
  • Git安装使用
  • Java增强for循环(小白友好版)
  • 整体设计 之“凝聚式中心点”原型 --整除:智能合约和DBMS的深层联合 之1
  • 【R语言】R语言矩阵运算:矩阵乘除法与逐元素乘除法计算对比
  • 7 索引的监控
  • 一文读懂[特殊字符] LlamaFactory 中 Loss 曲线图
  • JavaScript字符串详解
  • 图解希尔排序C语言实现
  • 力扣 hot100 Day76
  • Java 基础 -- Java 基础知识
  • C语言---第一个C语言程序
  • FreeRTOS源码分析八:timer管理(一)
  • 基于遗传编程的自动程序生成
  • Java语法进阶之常用类
  • SQL Server 2019安装教程(超详细图文)
  • PERCEIVER IO:一种用于结构化输入与输出的通用架构
  • iSCSI服务配置全指南(含服务器与客户端)
  • 快速掌握Hardhat与Solidity智能合约开发
  • SCAI采用公平发射机制成功登陆LetsBonk,60%代币供应量已锁仓
  • Houdini 粒子学习笔记