rust - Impl Send 用于 Bindgen 生成的指针类型
问题描述
我正在尝试将 FFI 指针类型发送到另一个线程。它指向的结构是由opensles-sys 中的 bindgen 生成的
这是我的包装器结构:
pub struct AndroidAudioIO {
sl_output_buffer_queue: NonNull<SLObjectItf>,
}
unsafe impl Send for AndroidAudioIO{}
该SLObjectItf
类型是一个别名,*const *const SLObjectItf_
其定义由 bindgen 生成。它是 FFI 函数指针的集合。
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SLObjectItf_ {
pub Realize: ::std::option::Option<
unsafe extern "C" fn(self_: SLObjectItf, async: SLboolean) -> SLresult,
>,
// More of the same pattern, only extern "C" function pointers, no data
}
我尝试添加unsafe impl Send for SLObjectItf_{}
和其他变体无济于事。
error[E0277]: `std::ptr::NonNull<*const *const opensles::bindings::SLObjectItf_>` cannot be shared between threads safely
--> src/lib.rs:12:1
|
12 | / lazy_static! {
13 | | static ref engine:Option<mynoise::Engine<Box<audio::AndroidAudioIO>>> = None;
14 | | }
| |_^ `std::ptr::NonNull<*const *const opensles::bindings::SLObjectItf_>` cannot be shared between threads safely
|
= help: within `audio::AndroidAudioIO`, the trait `std::marker::Sync` is not implemented for `std::ptr::NonNull<*const *const opensles::bindings::SLObjectItf_>`
= note: required because it appears within the type `audio::AndroidAudioIO`
我只关心Send
而不关心的原因Sync
是单个线程(RT音频线程)与这个结构交互,但它是在另一个线程上创建的,因此需要Send
指向正确线程的指针。
解决方案
下面的代码重现了同样的问题(假设Engine
只保留AndroidAudioIO
在类型级别,以便它可以在以后生成这样的处理程序;它也可以通过直接组合工作)。
#[macro_use]
extern crate lazy_static;
use std::marker::PhantomData;
use std::ptr::NonNull;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SLObjectItf;
pub struct AndroidAudioIO {
sl_output_buffer_queue: NonNull<SLObjectItf>,
}
unsafe impl Send for AndroidAudioIO {}
#[derive(Debug)]
pub struct Engine<T>(PhantomData<T>);
lazy_static! {
static ref engine: Option<Engine<AndroidAudioIO>> = None;
}
(游乐场)
这里的问题是该Engine
实体位于全局静态变量中,这立即使其在所有线程之间共享。这需要Sync
,但Engine
没有给出一个实现,Sync
因为AudioAndroidIO
没有实现Sync
。实际上,无论引擎是否包含作为属性的音频 I/O 处理程序,或者该信息仅存在于类型级别,甚至PhantomData
直接从其参数类型继承这些 trait 实现。引用文档:
impl<T: ?Sized> Send for PhantomData<T>
where
T: Send,
impl<T: ?Sized> Sync for PhantomData<T>
where
T: Sync
这很可能Engine
是可以拥有的情况Sync
(尽管PhantomData
选择了这种避免对内部类型假设的安全行为)。要解决这个问题,首先要绝对确保它Engine
是线程安全的。然后,为此手动实施Sync
。
unsafe impl<T> Sync for Engine<T> {}
我尝试添加
unsafe impl Send for SLObjectItf_{}
和其他变体无济于事。
好吧,无论如何,这通常是一个坏主意™。实现Send
和/或Sync
应该在绑定的安全、高级抽象之上完成。
推荐阅读
- reactjs - 最佳 React Router 登录实践
- javascript - html上的轮播图像未加载
- python - 而不是“休息”
- c# - 短跑运动问题
- php - 如何从分数显示排名到排行榜
- swift - 几个相关的结构类型如何在不使用 var 定义只读属性的情况下共享一个 init(...) 方法?
- java - 如何在不知道先验拆分字符的情况下拆分字符串?
- python - 将 reinterpret_cast 从 C++ 转换为 Python
- linux - 为什么打印 iwgetid 给我 0?
- c# - 使用 Amazon.Lambda.TestTool-3.1 (.NET) 时找不到 Libuv 1.10.0 dll