Need help passing closures between threads. error[E0277]: `(dyn Fn() + 'static)` cannot be sent between threads safely

On rust playground

So far tried boxing, Arcs, Arc Mutex, and various other solutions I found online, but I cannot get them to work.

error[E0277]: `(dyn Fn() + 'static)` cannot be sent between threads safely
   --> src\main.rs:192:19
    |
192 |       thread::spawn(move||  {
    |  _____-------------_^
    | |     |
    | |     required by a bound introduced by this call
193 | |         threade_state.lock().unwrap()
194 | |         .callback_store.callbacks.iter()
195 | |         .for_each(|(id, callback_arc)| {
...   |
199 | |         });
200 | |     }).join();
    | |_____^ `(dyn Fn() + 'static)` cannot be sent between threads safely
    |
    = help: the trait `Send` is not implemented for `(dyn Fn() + 'static)`
    = note: required for `Mutex<(dyn Fn() + 'static)>` to implement `Sync`
    = note: required for `Arc<Mutex<(dyn Fn() + 'static)>>` to implement `Send`
    = note: required because it appears within the type `(String, Arc<Mutex<(dyn Fn() + 'static)>>)`
    = note: required for `hashbrown::raw::RawTable<(String, Arc<Mutex<(dyn Fn() + 'static)>>)>` to implement `Send`
    = note: required because it appears within the type `hashbrown::map::HashMap<String, Arc<Mutex<(dyn Fn() + 'static)>>, RandomState>`
    = note: required because it appears within the type `HashMap<String, Arc<Mutex<(dyn Fn() + 'static)>>>`
use std::collections::HashMap;
use std::sync::{Mutex, Arc};
use std::thread;

struct CallbackStore {
    callbacks: HashMap<String, Arc<Mutex<dyn Fn() -> ()>>>
}

struct State {
    pub numbers: Vec<u64>,
    pub age_by_name: HashMap<String, u64>,
    pub callback_store: CallbackStore,
}

async fn callback_horror() {
    let mut state = Arc::new(Mutex::new(State {
        numbers: vec![1, 2, 3, 4, 5],
        age_by_name: HashMap::from([
            ("jeff".to_owned(), 42),
            ("joe".to_owned(), 43),
            ("doe".to_owned(), 29),
        ]),
        callback_store: CallbackStore {
            callbacks: HashMap::new(),
        },
    }));

    let add_state: Arc<Mutex<State>> = Arc::clone(&state);
    let mut add_callback = move || {
        let mut asd = add_state.lock().unwrap();
        asd.numbers.push(123);
    };
    state.lock().unwrap().callback_store.callbacks.insert(
        "adddomg_123_callback".to_owned(),
        Arc::new(Mutex::new(add_callback)));

    let delete_state: Arc<Mutex<State>> = Arc::clone(&state);
    let mut delete_callback = move || {
        state.lock().unwrap().age_by_name.remove("jeff");
    };
    state.lock().unwrap().callback_store.callbacks.insert(
        "delete_jeff_callback".to_owned(),
        Arc::new(Mutex::new(delete_callback)));

    let threade_state: Arc<Mutex<State>> = Arc::clone(&state);
    thread::spawn(move||  {
        threade_state.lock().unwrap()
        .callback_store.callbacks.iter()
        .for_each(|(id, callback_arc)| {
            println!("calling callback id: {}", id);
            let callback = callback_arc.lock().unwrap();
            callback();
        });
    }).join();

}

fn main() {
	callback_horror();
}

Nevermind, got it working: Rust Playground

Had to replace

    callbacks: HashMap<String, Arc<Mutex<dyn Fn() -> ()>>>

with

    callbacks: HashMap<String, Arc<Mutex<dyn Fn() + Send + 'static>>>
3 Likes