Running 2 longlived threads sharing same data

I am trying to create a service, which will be both shared by Rocket (to handle REST calls) and doing some logic on its own. Both use cases will manipulate data in Hashmap. To manage the struct Rocket requires it be static (T: Send + Sync + 'static). I tried to make static instance of Service, but I cannot do HashMap::new() - it break because calls in statics are limited to constant functions, tuple structs and tuple variants
My another try is:

#[macro_use]
extern crate rocket;

use scoped_threadpool::Pool;
use std::sync::Mutex;
use std::collections::HashMap;
use std::thread;
use std::time::Duration;


struct Service {
    pub data: HashMap<i32, Value>,
}

impl Service {
    // functions that let to manipulate data HashMap and and executed in both infinite loop and exposed in REST
    fn doSth(&mut self) {
        println!("Do something");
        self.data.clear();
    }
}

struct Value {
    pub value: String
}

fn main() {
    let service = Mutex::new(Service{data: HashMap::new()});

    let mut pool = Pool::new(4);
    pool.scoped(|s|
        {
            s.execute(|| infinite_loop(&service));
            s.execute(|| rocket_init(service));
        }
    );
}

fn infinite_loop(service: &Mutex<Service>) {
    loop {
        thread::sleep(Duration::from_secs(1));
        service.lock().unwrap().doSth();
    }
}

fn rocket_init(service: Mutex<Service>) {
    rocket::ignite()
        .manage(service)
        .mount("/", routes![
            // few endpoints using service
        ])
        .launch();
}

But it does not compile with because of: closure may outlive the current function, but it borrows service, which is owned by the current function

So I wonder what is correct approach to handle this in rust? Could the code above be fixed tackle the problem or the problem should be handled other way?

Put it in an Arc instead of trying to use references. Generally, I recommend defining a struct like this:

#[derive(Clone)]
pub struct Service {
    inner: Arc<Mutex<ServiceInner>>,
}

struct ServiceInner {
    data: HashMap<i32, Value>,
}

impl Service {
    pub fn do_sth(&self) {
        let mut lock = self.inner.lock().unwrap();
        println!("Do something");
        lock.data.clear();
    }
}

Now, because of the Arc, if you clone this Service, then you get a new Service object that shares the same hash map, and changes in one of them can be seen in all other clones as well.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.