I am trying to run multiple functions on different threads. I wrote this (minimal) code that works
use std::thread;
fn f1(count: usize) {
for i in 0..count { /*do something*/ }
}
fn f2(count: usize) {
for i in 0..count { /*do something*/ }
}
fn run(ops: &Vec<impl Fn(usize) Sync Send Copy 'static>) {
for i in 0..ops.len() {
let func = ops[i];
thread::spawn(move || func(1000));
}
}
fn main() {
let ops = vec![f1, f1]; // putting the same function twice
run(&ops);
}
However, as soon as I send different functions
let ops = vec![f1, f2];
Compiling fails. As I understand it, I cannot hold different types in the same vector (I guess, functions have different memory requirements, though I'm not quite sure how function pointers work).
I tried browsing similar questions on SO, and I tried this solution
let ops: Vec<&dyn Fn(usize)> = vec![&f1, &f2];
and I get this error
`dyn Fn(usize)` cannot be shared between threads safely
the trait `Sync` is not implemented for `dyn Fn(usize)`
And I'm stuck as I'm struggling to understand the base issue. Do you have insights on how I should understand this problem, and any pointers on how to solve it ?
Thank you!
CodePudding user response:
Just as you can add the Sync
marker with impl
, you can also add it with &dyn
, but you may need parenthesis to disambiguate:
fn run(ops: &Vec<&'static (dyn Fn(usize) Sync)>)
Two minor comments:
- Generally, using
&[…]
instead of&Vec<…>
is more flexible and to be preferred. - No need to do
for i in 0…foos.len()
in rust,for foo in foos
will do fine. (You may occasionally have to usefor foo in &foos
orfor foo in foos.iter()
. If you do need the index,.enumerate()
is convenient.) - If the
'static
is a bother (e.g. because you want to pass in some closure that captures local variables and can't be'static
), you could either use scoped threads (example), or pass ownedFn
s asVec<Box<dyn Fn(usize) Sync>>
.