I'm trying to write a simple Observer-pattern-ish thing with events and callbacks. The idea is that when the thing owning the mutating function dies (struct Obj {cb: Arc<Mutex<FnMut>>, .. }
), it drops the Arc
. After that, any Weak
references will be (effectively) dead and can be detected on access. I was ALSO hoping that this would decouple the FnMut
from Thread
's 'static
lifetime. I might need to wrap the whole thing in another Arc<Rwlock<T>>
to prevent the Weak
references from doing thread unsafe stuff, but that's a different problem.
The closest solution I've gotten was this: How can I send a function to another thread?
However, I seem to have the Arc<Mutex<T>>
and adding lifetimes (I may have done that wrong, though) didn't seem to help. I'm kind of lost as to what is actually wrong.
I wrote a minimal example:
use std::{
collections::HashMap,
sync::{
mpsc::{self, Receiver},
Arc, Mutex, Weak,
},
thread::{self, JoinHandle},
};
struct Callback {
cb_w: Weak<Mutex<FnMut()>>,
}
type FnMapping = Arc<HashMap<String, Callback>>;
fn start_thread<'a>(rx: Receiver<String>, mapping: FnMapping) -> JoinHandle<()> {
thread::spawn(move || {
match rx.recv() {
Ok(v) => {
if let Some(o) = mapping.get(&v) {
match o.cb_w.upgrade() {
Some(cb_m) => match cb_m.lock() {
Ok(cb_lg) => (*cb_lg)(),
Err(e) => (),
},
None => { /* TODO owner is gone, mark for delete */ }
}
}
}
Err(e) => (),
}
})
}
fn main() {
let mapping: FnMapping = Arc::new(HashMap::new());
let (tx, rx) = mpsc::channel();
drop(tx);
start_thread(rx, mapping)
.join()
.expect("Could not join thread -- failed to terminate?");
println!("Leaving the test bay.");
}
This fails to compile with the following error:
error[E0277]: `(dyn std::ops::FnMut() + 'static)` cannot be sent between threads safely
--> src/main.rs:17:5
|
17 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `(dyn std::ops::FnMut() + 'static)` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `(dyn std::ops::FnMut() + 'static)`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<(dyn std::ops::FnMut() + 'static)>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Weak<std::sync::Mutex<(dyn std::ops::FnMut() + 'static)>>`
= note: required because it appears within the type `Callback`
= note: required because it appears within the type `(std::string::String, Callback)`
= note: required because it appears within the type `std::marker::PhantomData<(std::string::String, Callback)>`
= note: required because it appears within the type `std::collections::hash::table::RawTable<std::string::String, Callback>`
= note: required because it appears within the type `std::collections::HashMap<std::string::String, Callback>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::collections::HashMap<std::string::String, Callback>>`
= note: required because it appears within the type `[closure@src/main.rs:17:19: 32:6 rx:std::sync::mpsc::Receiver<std::string::String>, mapping:std::sync::Arc<std::collections::HashMap<std::string::String, Callback>>]`
= note: required by `std::thread::spawn`