Lifetime issue: can't pass cloned Arc<RwLock<T>> into closure

I want an Axum request handler to launch some worker threads and let them run, but have a way to get a read lock on a shared Arc<RwLock<City>> object.

I don't see why this doesn't work. City is behind an Arc, so the worker thread can be sure the main thread doesn't destroy/drop City. The main thread can only drop its own reference to it.

How can I work around this?

type Res<T> = Result<T, Box<dyn Error>>;

#[derive(Clone)]
pub struct AppState {
	city: Arc<RwLock<City>>,
}

struct Poi { coord: Point }

#[derive(Clone)]
pub struct City {}

impl City {
    pub fn get_pois_coords(&self) -> Res<&Vec<Poi>> {
        todo!()
    }
}

async fn start_calculation(Path(()): Path<()>, State(ast): State<AppState>) -> Result<(HeaderMap, Bytes), (StatusCode, String)> {
    let city: Arc<RwLock<City>> = ast.city.clone();
    let bgwork = move || -> Res<()> {
        let ct: std::sync::RwLockReadGuard<'_, City> = city.read()?;
                                                       ^^^^^^^^^^^^
         returning this value requires that `'1` must outlive `'static`
         note: closure implements `Fn`, so references to captured variables can't escape the closure
 
        let pois: &Vec<Poi> = ct.get_pois_coords()?;
        drop(pois);
        todo!()
    };  
    todo!()
}

The issue is that with the ? operator you're trying to return the error from .read() from the closure. Given your definition of Res the error must be 'static, but the error from .read() is not 'static as it also contains a read guard.

You have a bunch of ways to handle this:

  • map the error to a new error type that doesn't borrow from anything
  • ignore the error and extract the read guard from it in case this happens
  • unwrap the result

When making this choice consider that .read() will return an error only when another thread/task previously panicked while holding the lock.

6 Likes

Thanks you very much!

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.