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 `[[email protected]: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());
}
}
lazy_static and once_cell serve the same purpose. The error isn't crate-specific. Unless the title is wrong, once_cell::sync::Lazy is not threadsafe, and lazy_static definitely is. In addition, that same title suggests mutability because thread safety is not an issue if there are only readers.
Mutex is in fact a “ Sync -maker”. It makes a Sync wrapper of a sendable type that is otherwise not Sync, like for example Sender (sender end of a channel).
If you need mutability, put a Cell or RefCell inside the Rc ; see an example of mutability inside an Rc . Rc uses non-atomic reference counting. This means that overhead is very low, but an Rc cannot be sent between threads, and consequently Rc does not implement Send .
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With