Why both ot the two can't compiled

I used move in closure, and uc2: Send
But I can't make the both compiled
Saying uc2: !Sync........... why move has no effect here? even in case of let x = uc2 can't make uc2 moved into the closure.

#[test]         

fn a() {                                                            
    use std::thread;                                                
    let mut uc = std::sync::Arc::new(std::cell::UnsafeCell::new(9));                                                                    
    let uc2 = uc.clone();                                           
    let j = thread::spawn(move || {                                                                             
        *uc2.get_mut() = 100;                                         
    });                                                             
    j.join();                                                       
}  
                                                    
fn b() {                                                            
    use std::thread;                                                
    let mut uc = std::sync::Arc::new(std::cell::UnsafeCell::new(9));                                                                    
    let uc2 = uc.clone();                                           
    let j = thread::spawn(move || {                                 
        let x = uc2;                                                
        *x.get_mut() = 100;                                         
    });                                                             
    j.join();                                                       
}   

Don't use UnsafeCell directly, instead use Mutex, or for integers you could use atomics. If you need the performance (but measure first).

With mutex your code will look like:

use std::sync::{Arc, Mutex};

#[test]
fn a() {                                                            
    use std::thread;                                                
    let mut uc = Arc::new(Mutex::new(9));                                                                    
    let uc2 = uc.clone();                                           
    let j = thread::spawn(move || {                                                                             
        *uc2.lock().unwrap() = 100;                                         
    });                                                             
    j.join();                                                       
}  
                                                    
fn b() {                                                            
    use std::thread;                                                
    let mut uc = Arc::new(Mutex::new(9));                                                                    
    let uc2 = uc.clone();                                           
    let j = thread::spawn(move || {                                 
        let x = uc2;                                                
        *x.lock().unwrap() = 100;                                         
    });                                                             
    j.join();                                                       
}

You can't use UnsafeCell<T> because it doesn't synchronize access to T. So it's not thread-safe on it's own. So you can't share it among different threads.

Mutex does syncronize access to T, so you can share it among different threads.

Note that Arc allows you to share ownership, so sending an Arc to another thread requires that you can share T. I.e. Arc<T>: Send if T: Sync + ...

2 Likes