Почему я не могу отправить Mutex <* mut c_void> между потоками? - PullRequest
0 голосов
/ 19 февраля 2020

Мне нужно разделить объект, созданный из C ++, между потоками Rust. Я обернул его в конструкцию Mutex, так что теперь его можно безопасно передавать между потоками. Однако компилятор не позволяет мне делать то, что.

error[E0277]: `*mut std::ffi::c_void` cannot be sent between threads safely
   --> sendsync.rs:14:2
    |
14  |     thread::spawn(move || {
    |     ^^^^^^^^^^^^^ `*mut std::ffi::c_void` cannot be sent between threads safely
    |
    = help: within `Api`, the trait `std::marker::Send` is not implemented for `*mut std::ffi::c_void`
    = note: required because it appears within the type `OpaqWrapper`
    = note: required because it appears within the type `Api`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<Api>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::Mutex<Api>>`
    = note: required because it appears within the type `[closure@sendsync.rs:14:16: 19:3 safe_obj:std::sync::Arc<std::sync::Mutex<Api>>]`

Как мне реализовать это в соответствии с правилами Rust? Вот код:

use std::{
    sync::{
        Arc,Mutex,
    },
    ptr,
    thread::{self},
};
pub struct OpaqWrapper {
    pub obj_ptr: *mut ::std::os::raw::c_void,
}
pub struct Api(OpaqWrapper);

fn spawn_api_thread(safe_obj: Arc<Mutex<Api>>) {
    thread::spawn(move || {
        {
            let my_api = safe_obj.lock().unwrap();
            // my_api.whatever();
        }
    });
}

fn main() {
    let api = Api(
        OpaqWrapper {
            obj_ptr: ptr::null_mut(),
        }
    );
    let shared_api= Arc::new(Mutex::new(api));
    for _ in 0..10 {
        spawn_api_thread(shared_api.clone());
    }
}

1 Ответ

2 голосов
/ 19 февраля 2020

Короткая версия

Для передачи чего-либо в поток требуется, чтобы оно было Send.

T:Send => Mutex<T>:Send+Sync =>  Arc<Mutex<T>>:Send

, поэтому достаточно пометить Api как Send

Длинная версия

Для передачи чего-либо в поток требуется, чтобы оно было Send.

Arc<T> только автоматически получает SendSync), если T равно Send и Sync. Источник содержит что-то вроде этого:

unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}

Однако для Mutex требуется только Send, чтобы оно было и Sync, и Send, его код содержит:

unsafe impl<T: ?Sized + Send> Send for Mutex<T> { }
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }

Это означает, что Arc<Mutex<Api>> должно быть Sync, вам нужно Mutex<Api>, чтобы быть Sync+Send, что произойдет, если Api будет Send. Для этого вам нужно пометить Api или OpaqWrapper как Send.

unsafe impl Send for Api {}

Обратите внимание, что вам не нужно отмечать их как Sync, поскольку Mutex получает это автоматически.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...