How do I emulate a timer inside an object that wil

2019-08-19 01:44发布

问题:

In my project I need to do something like:

use std::thread;
use std::time::Duration;

struct A {
    pub ints: Vec<u8>,
}

impl A {
    fn new() -> A {
        let mut a = A {
            ints: vec![1, 5, 6, 2, 3, 4],
        };
        a.timer();
        a
    }

    fn timer(&mut self) {
        thread::spawn(move || {
            loop {
                thread::sleep(Duration::from_millis(1));
                self.ints.remove(0);
            }
        });
    }
}

fn main() {
    let a = A::new();
    loop {
        println!("Remaining elements: {:?}", a.ints);
    }
}

The idea is that some struct contains a vector of elements. These elements should be removed from the vector after some period of time. Think of it as a periodic timer that checks something and performs an action on mutable object (removes an element). This thread also needs to be dropped if the object on which it is working on is deleted. So I guess it should be a member of a struct of which it is manipulating.

The problem with the code above is that it has a lot of borrow errors and I don't understand how to do that.

I have seen few questions like this but each of them was about manipulating scalar in a thread. The reason why I can't apply it here is because the thread should be something that is inside A struct and it should call remove on a vector that is a member of that struct.

I guess I should use Arc or something like that but don't really understand how to use it here.

回答1:

I guess I should use Arc or something like that but don't really understand how to use it here.

Indeed that is the simplest solution:

You can wrap the ints field in an Arc, but then you wouldn't be able to modify the Vec, so you also wrap it in a Mutex:

struct A {
    pub ints: Arc<Mutex<Vec<u8>>>,
}

Then you can clone the Arc to receive a second handle to the same memory.

fn timer(&mut self) {
    let ints = self.ints.clone();
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_millis(1));

Instead of directly accessing the Vec, you then need to lock the Mutex, which can fail if another thread panicked while accessing the Mutex.

            ints.lock().unwrap().remove(0);
        }
    });
}