Search code examples
c++rustffivoid-pointersrust-bindgen

How to send a pointer to another thread?


I created a Rust wrapper for a C++ library for a camera using bindgen, and the camera handle in the C++ library is defined as typedef void camera_handle which bindgen ported over as:

pub type camera_handle = ::std::os::raw::c_void;

I'm able to successfully connect to the camera and take images, however I wanted to run code on a separate thread for temperature control of the camera, essentially changing the cooler power based on the current temperature of the camera, which I want to have run separately from the rest of the code. These calls require the camera handle, but when I spawn a new thread, I keep getting the error:

'*mut std::ffi::c_void' cannot be sent between threads safely

And underneath it, it mentions:

the trait 'std::marker::Send' is not implemented for '*mut std::ffi::c_void'

How can I send this to another thread so I can use this camera handle there as well? I have tried using fragile and send_wrapper, but have been unsuccessful with both of them.


Solution

  • Pointers do not implement Send or Sync since their safety escapes the compiler. You are intended to explicitly indicate when a pointer is safe to use across threads. This is typically done via a wrapper type that you implement Send and/or Sync on yourself:

    struct CameraHandle(*mut c_void);
    
    unsafe impl Send for CameraHandle {}
    unsafe impl Sync for CameraHandle {}
    

    Since implementing these traits manually is unsafe, you should be extra diligent to ensure that the types from the external library actually can be moved another thread (Send) and/or can be shared by multiple threads (Sync).

    If you ever take advantage of the pointer's mutability without the protection of &mut self, it should probably not be Sync since having two &mut T at the same time is always unsound.

    See: