How to share a raw pointer between threads?

I'm writing some parallel computing code using rayon and need the threads to access some shared mutable state. Compiler says no so I plan to use the superpower of unsafe and share a raw pointer between threads and dereference it in the thread.

Now that *mut T is !Send and !Sync, I need to make a wrapper struct and mark it as Sync and share that struct between threads. But following code doesn't compile. playground

use rayon::prelude::*;

struct PtrWrapper(*const ());

unsafe impl Sync for PtrWrapper {}

fn main() {
    let ptr_wrapper = PtrWrapper(&() as _);
    (0..10).into_par_iter().for_each(|_| {
        ptr_wrapper.0;
    });
}

Compiler says

`*const ()` cannot be shared between threads safely

But I'm not sharing *const (). I'm sharing PtrWrapper. What am I doing wrong?

Add a line

let _ = &ptr_wrapper;

inside of the closure to avoid the smarter new fine-grained closure capturing.

1 Like

Don't. Use a safe synchronization mechanism (atomics or locks) instead.

You are. Since you are only accessing a single field of the PtrWrapper, the compiler tries to partially borrow it.

You probably shouldn't use unsafe for those reasons. You should instead use some locking mechanisms (Arc<Mutex<T>> typically) or communicate via channels:

let state = 1;
let (sender, receiver) = crossbeam::channel::bounded(64);
let (a, _) = rayon::join(
    move || {
        // do something with the receiver and your state
    },
    move || {
        (0..10).into_par_iter().for_each_with(sender, |sender, i| {
            sender.send(i).unwrap()
        });
    }
);
1 Like

Thanks guys for your suggestion on "don't do this". I'm intentionally not using Mutex or channel because the code is going to compile to both spirv and cpu. All I have is limited form atomics.

Neat! I wish someday we can explicitly control what's captured like in C++.