Home > Software engineering >  add lifetime for a struct that invoke method in multi-threading environment
add lifetime for a struct that invoke method in multi-threading environment

Time:12-13

This is my program:

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

trait Animal: Send   Sync { fn get_id(&self) -> i32; }

struct Cat {}

impl Animal for Cat {
    fn get_id(&self) -> i32 { return 0; }
}

struct Thread {
    id: i32,
    ptr: Arc<dyn Animal>,
}

impl Thread {
    pub fn multi_threading(&self) {
        let shared_array = Arc::new(Mutex::new([0; 5]));
        let mut handles = vec![];
        for _ in 0..5 {
            let array_ptr = Arc::clone(&shared_array);
            let handle = thread::spawn(move ||
                self.assign(&mut array_ptr.lock().unwrap())
            );
            handles.push(handle);
        }
        for handle in handles {
            handle.join().unwrap();
        }
    }

    pub fn assign(&self, array: &mut MutexGuard<[i32; 5]>) {
        array[self.id as usize] = self.id * self.id   self.ptr.get_id();
    }
}

unsafe impl Send for Thread {}

fn main() {
    let cat = Cat {};
    let ptr_cat = Arc::new(cat);
    let thread = Thread { id: 0, ptr: ptr_cat.clone() };
    thread.multi_threading();
}

struct Thread is defined with a pointer to a trait object, its member method multi_threading does nothing but assigning value to an array that can be accessed by several threads.

When I compile the program, the error says the &self from pub fn multi_threading(&self)

has an anonymous lifetime '_ but it needs to satisfy a 'static lifetime requirement

Now where should I add this 'static lifetime to satisfy the requirement, to get the program complied?

CodePudding user response:

You can wrap your instance in an Arc itself. That way you can send it to your threads:

impl Thread {
    pub fn multi_threading(self: &Arc<Self>) {
        let shared_array = Arc::new(Mutex::new([0; 5]));
        let mut handles = vec![];
        for _ in 0..5 {
            let array_ptr = Arc::clone(&shared_array);
            let s = self.clone();
            let handle = thread::spawn(move ||
                s.assign(&mut array_ptr.lock().unwrap())
            );
            handles.push(handle);
        }
        for handle in handles {
            handle.join().unwrap();
        }
    }

    pub fn assign(&self, array: &mut MutexGuard<[i32; 5]>) {
        array[self.id as usize] = self.id * self.id   self.ptr.get_id();
    }
}
...

fn main() {
    let cat = Cat {};
    let ptr_cat = Arc::new(cat);
    let thread = Arc::new(Thread { id: 0, ptr: ptr_cat.clone() });
    thread.multi_threading();
}

Playground

Notice that you would not need unsafe impl Send for Thread {}, because with Arc it is safe to share it.

  • Related