Putting `self` into an `Arc` in Rust

Viewed 1388

I have a Rust struct with a method that is designed to parallelise over multiple threads. Each thread needs to access that struct. So naturally I want to put it into an Arc. However I can't work out a way to do this.

Here's a simplified example:

use std::sync::{Arc};
use std::thread;
struct Foo {
    field: usize
}
impl Foo {
    fn parallel(&self){
        let arc = Arc::new(&self);
        for i in 1..5 {
            let arc = Arc::clone(&arc);
            thread::spawn(move || {
                i + arc.field
            });
        }
    } 
}

And the compiler says:

    fn parallel(&self){
                ^^^^^ this data with an anonymous lifetime `'_`...
        let arc = Arc::new(&self);
                           ^^^^^ ...is captured here...
            thread::spawn(move || {
            ^^^^^^^^^^^^^ ...and is required to live as long as `'static` here
`self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement

So it would seem that I'm actually not allowed to put self into an Arc (not quite sure why, though).

I've also tried cloning self but that gives the same error:

impl Foo {
    fn parallel(&self){
        let clone = self.clone();
        let arc = Arc::new(&clone);
        for i in 1..5 {
            let arc = Arc::clone(&arc);
            thread::spawn(move || {
                i + arc.field
            });
        }
    } 
}
    fn parallel(&self){
                ^^^^^ this data with an anonymous lifetime `'_`...
        let clone = self.clone();
                         ^^^^^ ...is captured here...
            thread::spawn(move || {
            ^^^^^^^^^^^^^ ...and is required to live as long as `'static` here
`self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement

Similar things happen if I try to move the clone into the Arc, or if I remove the move in front of the closure.

What is going on here, and how can I fix it? Also, in general, is there any way to do this: ie putting self into an Arc, where self is a struct?

1 Answers

If you put self or &self in the arc, you have to take it back at the end of the function.

It means you can't let it to the other threads.

The crossbeam crate includes a facility to deal with exactly this: ensure the threads release what you gave them:

Creates a new scope for spawning threads.

All child threads that haven’t been manually joined will be automatically joined just before this function invocation ends. If all joined threads have successfully completed, Ok is returned with the return value of f. If any of the joined threads has panicked, an Err is returned containing errors from panicked threads.

Example:

use std::sync::{Arc};
use crossbeam::thread;
struct Foo {
    field: usize
}
impl Foo {
    fn parallel(&self){
        let arc = Arc::new(&self);
        for i in 1..5 {
            let arc = Arc::clone(&arc);
            thread::scope(|s| {
                s.spawn(|_| {
                    i + arc.field
                });
            });
        }
    }
}
Related