简体   繁体   中英

Why can't I send Mutex<*mut c_void> between threads?

I need to share an object created from C++ between Rust threads. I have wrapped it in a Mutex construct, so now it is safe to be sent between threads. However the compiler won't let me do what.

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>>]`

How should I implement this according to Rust rules? Here is the code:

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());
    }
}

Short version

Passing something to a thread requires that it be Send .

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

so it is enough to mark Api as Send

Long version

Passing something to a thread requires that it be Send .

Arc<T> only automatically gets Send (and Sync ) if T is Send and Sync . The source contains something like this:

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

However, Mutex only requires Send for it to be both Sync and Send , its code contains:

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

This means for Arc<Mutex<Api>> to be Sync , you need Mutex<Api> to be Sync+Send which will happen if Api is Send . To get this you need to mark either Api or OpaqWrapper as Send .

unsafe impl Send for Api {}

Note you dont need to mark them as Sync as the Mutex gets that automatically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM