You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust无法给回调新增参数时如何访问含非Send类型的全局状态

解决方案

单线程场景快速实现

使用thread_local!定义线程局部静态变量,线程局部存储不需要满足Send/Sync约束,完全适配当前单线程运行的场景,不需要修改FFI结构体的安全标记:

use std::cell::RefCell;
use std::collections::HashMap;
use std::time::Instant;
use lib::bar;

struct Struct2{
    foo: bar,
    word: String,
}

struct GlobalState{
    running: bool,
    now: Instant,
    map: HashMap<String, Struct2>,
    hook_id: usize,
    current_id: String,
}

// 线程局部静态变量,仅初始化线程可访问
thread_local! {
    static GLOBAL_STATE: RefCell<GlobalState> = RefCell::new(GlobalState::init());
}

impl GlobalState{
    fn init() -> Self{
        let hook_id = unsafe { set_ext_hook(HOOK_ID, system_hook) };
        Self {
            running: false,
            now: Instant::now(),
            map: Default::default(),
            hook_id,
            current_id: Default::default(),
        }
    }
}

unsafe extern "system" fn system_hook(ext_param1:usize, ext_param2: usize) -> isize {
    GLOBAL_STATE.with(|state| {
        let mut state = state.borrow_mut();
        // 直接读写全局状态即可
        state.running = true;
    });
    0
}

多线程兼容实现

如果后续需要新增GUI线程跨线程访问状态,可以手动为包含非安全标记FFI结构体的GlobalState实现Send/Sync,只需确认在加锁访问的场景下lib::bar不会产生数据竞争:

use once_cell::sync::Lazy;
use std::sync::Mutex;
use std::collections::HashMap;
use std::time::Instant;
use lib::bar;

struct Struct2{
    foo: bar,
    word: String,
}

struct GlobalState{
    running: bool,
    now: Instant,
    map: HashMap<String, Struct2>,
    hook_id: usize,
    current_id: String,
}

// 手动标记线程安全,需自行确认lib::bar加锁访问无并发问题
unsafe impl Send for GlobalState {}
unsafe impl Sync for GlobalState {}

static GLOBAL_STATE: Lazy<Mutex<GlobalState>> = Lazy::new(|| {
    Mutex::new(GlobalState::init())
});

impl GlobalState{
    fn init() -> Self{
        let hook_id = unsafe { set_ext_hook(HOOK_ID, system_hook) };
        Self {
            running: false,
            now: Instant::now(),
            map: Default::default(),
            hook_id,
            current_id: Default::default(),
        }
    }
}

unsafe extern "system" fn system_hook(ext_param1:usize, ext_param2: usize) -> isize {
    let mut state = GLOBAL_STATE.lock().unwrap();
    // 读写全局状态
    state.running = true;
    0
}

注意事项

  • 线程局部变量只能在初始化它的线程中访问,跨线程调用会触发panic,适合单线程快速验证逻辑使用
  • 手动实现Send/Sync属于unsafe操作,必须确认lib::bar的内部实现不会在加锁并发访问时产生数据竞争,常见的FFI导出无内部共享状态的类型都满足该要求
  • 全局状态必须通过内部可变性容器包裹:单线程用RefCell,多线程用Mutex/RwLock,否则无法执行修改操作

内容的提问来源于stack exchange,提问作者Ahmad AlHallak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 08:06:04