Gatonito
Gatonito

Reputation: 2174

Getting deadlock inside match of async function

I'm getting a deadlock on the following example:

use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use futures::lock::Mutex;
use std::sync::Arc;

struct A{
    
}

impl A {
    pub async fn do_something(&self) -> std::result::Result<(), ()>{
        Err(())
    }
}

async fn lock_and_use(a: Arc<Mutex<A>>) {
    match a.clone().lock().await.do_something().await {
        Ok(()) => {
            
        },
        Err(()) => {
            //try again on error
            println!("trying again");
            a.clone().lock().await.do_something().await.unwrap();
        }
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("begin");
    let a = Arc::new(Mutex::new(A{}));
    lock_and_use(a.clone()).await;
    println!("end");
    Ok(())
}

Playground

If I did this:

a.clone().lock().await.do_something().await;
a.clone().lock().await.do_something().await;

there would be no problem, the lock() dies on the same line it's created. I thought this principle would be the same for match. If you think about match, it locks the value, calls do_something, awaits on it, and then compares the value. It's true that do_something returns a future which capture the self, but when we await on it, it should discard the self. Why it still holds self? How can I solve this without cloning the result?

Upvotes: 1

Views: 547

Answers (1)

Stargateur
Stargateur

Reputation: 26757

Yes:

Temporaries live for the entire statement, never shorter.

Cause code could be:

{
    match self.cache.read() { // <-- direct pattern matching
        Ok(ref data) => Some(data)
        _ => None,
    }
}.map(|data| {
    // use `data` - the lock better be held
})

Read this issue for more detail.

So you need to lock outside your match statement:

let x = a.clone().lock().await.do_something().await;
match x {
    Ok(()) => {}
    Err(()) => {
        a.clone().lock().await.do_something().await.unwrap();
    }
}

Upvotes: 2

Related Questions