0

I am trying to declare and read/write an instance of a custom struct, using lazy_static as I had to use non-const function at its initialization (string).

As I saw here in an other Stackoverflow post, I tried to use RwLock, which works fine when it comes to write, but fails when it comes to read, with the following error:

thread 'main' panicked at 'rwlock read lock would result in deadlock', /Users/adrien/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/sys/unix/rwlock.rs:47:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
pub struct Authentication {
    access_token: String,
    refresh_token: String,
    expiration: u32
}

lazy_static! {
    static ref LATEST_AUTH: RwLock<Authentication> = RwLock::new(Authentication {
        access_token: "access".to_string(),
        refresh_token: "refresh".to_string(),
        expiration: 0
    });
}

pub fn auth(){
   let api_resp: ApiResponse = res.json().unwrap(); //From a reqwest res
   let mut au = LATEST_AUTH.write().unwrap();
   au.access_token = api_resp.access_token.clone();
   println!("LATEST_AUTH:{}", LATEST_AUTH.read().unwrap()); //Fails
}
5
  • You are still holding the write lock when you're trying to get a read lock. You'd have to drop the write lock first. Write locks also permit reading, so you don't actually need it. Commented Oct 19, 2020 at 7:44
  • Thanks, so I can just access au. Just to be curious, but how I can drop the write lock? Commented Oct 19, 2020 at 7:53
  • "Holding" the lock means that there is a lock guard in scope. You need to drop the write lock to unlock it, before you can lock it again for reading. Commented Oct 19, 2020 at 8:13
  • In your case au lives for the entire auth function, which means that you can't also lock it for reading. However, as mcarton says, you can read from a write lock, the easiest fix is to au for reading too, instead of acquiring a new read lock. Commented Oct 19, 2020 at 8:15
  • The other fix would be to drop au manually, e.g, with std::mem::drop(au);. Commented Oct 19, 2020 at 8:16

1 Answer 1

3

A RwLock is locked for the entire scope of the lock guard, which is obtained from calls to read() or write().

In your case, the write lock guard, au, lives for the entire duration of the auth function. This is what the error is saying: you've already locked it and then trying to lock it again in the same thread will make it block forever.

Write locks can also be used for reading, so you can fix this by just re-using that instead of trying to lock it again:

pub fn auth(){
   let api_resp: ApiResponse = res.json().unwrap();
   let mut au = LATEST_AUTH.write().unwrap();
   au.access_token = api_resp.access_token.clone();
   println!("LATEST_AUTH:{}", au);
}

Alternatively, you can force the lock to be dropped sooner, so that you can lock it for reading separately:

pub fn auth(){
   let api_resp: ApiResponse = res.json().unwrap();
   let mut au = LATEST_AUTH.write().unwrap();
   au.access_token = api_resp.access_token.clone();
   std::mem::drop(au);
   println!("LATEST_AUTH:{}", LATEST_AUTH.read().unwrap());
}

Or:

pub fn auth(){
   let api_resp: ApiResponse = res.json().unwrap();
   // a new scope
   {
       let mut au = LATEST_AUTH.write().unwrap();
       au.access_token = api_resp.access_token.clone();
       // au will be dropped here, when it goes out of scope
   }
   println!("LATEST_AUTH:{}", LATEST_AUTH.read().unwrap());
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.