gpt4 book ai didi

rust - 为 Bindgen 生成的指针类型实现 Impl Send

转载 作者:行者123 更新时间:2023-11-29 08:34:47 26 4
gpt4 key购买 nike

我正在尝试将 FFI 指针类型发送到另一个线程。它指向的结构已由 bindgen 生成 from opensles-sys

这是我的包装器结构:

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音频线程)与这个结构交互,但它是在另一个线程,因此需要将指针发送到正确的线程。

最佳答案

下面的代码重现了同样的问题(假设 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;
}

( Playground )

这里的问题是这个 Engine 实体在一个全局静态变量中,这立即使它在所有线程之间共享。这需要 Sync,但是 Engine 没有得到 Sync 的实现,因为 AudioAndroidIO 没有实现 Sync 。事实上,无论引擎是否包含音频 I/O 处理程序作为属性,或者该信息仅存在于类型级别,即使是 PhantomData直接从其参数类型继承这些特征实现。引用文档:

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> {}

I tried adding unsafe impl Send for SLObjectItf_{} and other variants to no avail.

嗯,无论如何,这通常是一个坏主意™。实现 Send 和/或 Sync 应该在绑定(bind)的安全、高级抽象之上完成。

关于rust - 为 Bindgen 生成的指针类型实现 Impl Send,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52531109/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com