2

I'd like to share a struct with an Arc<Mutex<Fn(i64)>> through a thread. I've minimally reproduced the problem below:

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

struct NonSendable {
    problematic: Arc<Mutex<Fn(i64)>>,
}

fn main() {
    let bad = NonSendable {
        problematic: Arc::new(Mutex::new(|i| println!("{}", i))),
    };

    std::thread::spawn(|| {
        for i in 0..10 {
            let f = bad.problematic.lock().unwrap();
            f(i);
        }
    });
}

However, this errors on compilation.

error[E0277]: `(dyn std::ops::Fn(i64) + 'static)` cannot be sent between threads safely
  --> src/main.rs:13:5
   |
13 |     std::thread::spawn(|| {
   |     ^^^^^^^^^^^^^^^^^^ `(dyn std::ops::Fn(i64) + 'static)` cannot be sent between threads safely
   |
   = help: the trait `std::marker::Send` is not implemented for `(dyn std::ops::Fn(i64) + 'static)`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<(dyn std::ops::Fn(i64) + 'static)
>`
   = note: required because of the requirements on the impl of `std::marker::Sync` for `std::sync::Arc<std::sync::Mutex<(dyn std::ops::Fn(
i64) + 'static)>>`
   = note: required because it appears within the type `NonSendable`
   = note: required because of the requirements on the impl of `std::marker::Send` for `&NonSendable`
   = note: required because it appears within the type `[closure@src/main.rs:13:24: 18:6 bad:&NonSendable]`
   = note: required by `std::thread::spawn`

error: aborting due to previous error

I guess I might understand why a Fn isn't Send or Sync, but should a Mutex not cover that issue? I've also tried to Box the Fn and use FnMut instead.

The end goal here is to have a Vec of closures that can be accessed and modified in one thread while read in another thread, so I think I need multiple non-mut references (or maybe an Arc) to coexist in different threads with an Arc<Mutex<Vec<Fn>>> or similar as a member, but if I can't get the above to work I'll have to use a different strategy.

0

1 Answer 1

0

Figured it out very shortly after I asked (though I'd been thinking about it for a day).

Fn is just a trait, which itself does not add Send. However, closures are also Send, so I need to replace Mutex<Fn(i64)> with Mutex<Fn(i64) + Send>. This reveals other problems, but solves the original one.

Sign up to request clarification or add additional context in comments.

2 Comments

It occurs to me that, while this fixes the code, it doesn't really explain to me why Mutex<ActuallyUnsendable> wouldn't be Send. I'd be interested to hear an answer that also explains this.
That second part is answered here. Mutex does not automatically make something safe to use in a multi-threaded environment.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.