Rust 如何正确地互斥锁从C调用的蹦床使用的结构

Rust 如何正确地互斥锁从C调用的蹦床使用的结构,rust,Rust,我在C代码中使用这种技术,从Rust调用,调用Rust的方法 pub type OnVpnLog = std::sync::Arc<std::sync::Mutex<dyn Fn(*const libc::c_char) + Send + Sync>>; pub type OnVpnSomething = std::sync::Arc<std::sync::Mutex<dyn Fn(i32) + Send + Sync>>; struct OVP

我在C代码中使用这种技术,从Rust调用,调用Rust的方法

pub type OnVpnLog = std::sync::Arc<std::sync::Mutex<dyn Fn(*const libc::c_char) + Send + Sync>>;
pub type OnVpnSomething = std::sync::Arc<std::sync::Mutex<dyn Fn(i32) + Send + Sync>>;

struct OVPNClientInner {
    on_vpn_log: Option<OnVpnLog>,
    on_vpn_something: Option<OnVpnSomething>,
}

unsafe extern "C" fn on_log_trampoline(
    buffer: *const libc::c_char,
    user_data: *mut libc::c_void,
) -> libc::c_int {
    let ovpn_client_inner = &mut *(user_data as *mut OVPNClientInner);

    (ovpn_client_inner.on_vpn_log.as_ref().unwrap().lock().unwrap())(buffer);
    0
}

unsafe extern "C" fn on_something_trampoline(
    user_data: *mut libc::c_void,
) -> libc::c_int {
    let ovpn_client_inner = &mut *(user_data as *mut OVPNClientInner);

    (ovpn_client_inner.on_vpn_something.as_ref().unwrap().lock().unwrap())(0);
    0
}
但是,
OVPNClientInner
在C和Rust之间共享,因此不能存在ffi不安全类型。另外,当我们试图锁定互斥锁时,互斥锁可以被更改(也许我们可以使它不可变,我不知道)


这里有什么好的解决方案可以提供良好的安全性?

如果vpn日志上的
和vpn上的
可以单独更新和使用,我建议:

pub type OnVpnLog = dyn Fn(*const libc::c_char) + Send + Sync;
pub type OnVpnSomething = dyn Fn(i32) + Send + Sync;

struct OVPNClientInner {
    on_vpn_log: Mutex<Option<Box<OnVpnLog>>>,
    on_vpn_something: Mutex<Option<Box<OnVpnSomething>>>,
}
但是,
OVPNClientInner
在C和Rust之间共享,因此不能存在ffi不安全类型

我不熟悉这个API,但通常称为“用户数据”的不透明的
void*
被框架本身使用。ffi边界为
void*
且在C端未使用意味着在您的结构中使用
Mutex
并不重要,实际上您可以放置几乎任何东西

您唯一应该关心的是,您发送的是否是
Sync
,这意味着从多个线程使用它是安全的。在这方面,上述两种实现都是安全的


另外,您当前有一个假定存在的
选项。您应该删除它,或者确保正确处理它的缺失。

总而言之,您担心的是这些函数可以同时从多个线程调用?@kmdreko是的,可能还有其他我没有意识到的问题
pub type OnVpnLog = dyn Fn(*const libc::c_char) + Send + Sync;
pub type OnVpnSomething = dyn Fn(i32) + Send + Sync;

struct OVPNClientInner {
    on_vpn_log: Mutex<Option<Box<OnVpnLog>>>,
    on_vpn_something: Mutex<Option<Box<OnVpnSomething>>>,
}
struct OVPNClientInner {
    on_vpn_log: Option<Box<OnVpnLog>>,
    on_vpn_something: Option<Box<OnVpnSomething>>,
}

unsafe extern "C" fn on_log_trampoline(
    buffer: *const libc::c_char,
    user_data: *mut libc::c_void,
) -> libc::c_int {
    let ovpn_client_inner = &*(user_data as *mut Mutex<OVPNClientInner>); // <--------
    
    (ovpn_client_inner.lock().unwrap().on_vpn_log.as_ref().unwrap())(buffer);
    0
}