Why closure complains about UnsafeCell that I access through Sync structure?

Minimized code:

use std::cell::UnsafeCell;

fn run_in_threads<F>(f: F)
where
    F: Fn() -> () + Sync,
{
}

fn function2() {
    struct Buffer {
        values: Vec<UnsafeCell<i32>>,
    }
    // I am implementing synchronization externally
    unsafe impl Sync for Buffer {}

    let buffer = Buffer {
        values: (0..128usize * 1024 * 1024)
            .map(|_| UnsafeCell::new(0))
            .collect(),
    };

    // Why it says that the closure is not Sync
    // because of UnsafeCell when UnsafeCell is
    // wrapped into a Sync structure?
    run_in_threads(|| {
        let x = 0;
        unsafe {
            *buffer.values[x].get() = 0;
        }
    });
}

Error message:

error[E0277]: `UnsafeCell<i32>` cannot be shared between threads safely
   --> src/lib.rs:21:20
    |
21  |       run_in_threads(|| {
    |       -------------- ^-
    |       |              |
    |  _____|______________within this `{closure@src/lib.rs:21:20: 21:22}`
    | |     |
    | |     required by a bound introduced by this call
22  | |         let x = 0;
23  | |         unsafe {
24  | |             *buffer.values[x].get() = 0;
25  | |         }
26  | |     });
    | |_____^ `UnsafeCell<i32>` cannot be shared between threads safely

This is incorrect error because I wrapped UnsafeCell into a Sync structure so it should be irrelevant that UnsafeCell itself is not Sync.

How can I workaround this?

Adding let buf = &buf; before calling run_in_threads helped.

The reason is that due to capturing distinct fields, the closure captures a &Vec<UnsafeCell<i32>>, not a &Buffer.

4 Likes

Thanks!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.