Integrate Mutex and MutexGuard into a struct

use std::sync::{Mutex, MutexGuard};
use std::option::Option;

struct Proc<'a> {
    lock: Mutex<()>,
    _guard: Option<MutexGuard<'a, ()>>,
}

impl<'a> Proc<'a> {
    fn new() -> Self {
        Self {
            lock: Mutex::new(()),
            _guard: None,
        }
    }
    
    fn lock(&mut self) {
        println!("process is locking");
        self._guard = Some(self.lock.lock().unwrap());
    }
    
    fn unlock(&mut self) {
        println!("process is unlocking");
        self._guard = None;
    }
}

fn main() {
    let p = Proc::new();
    // let _lock1 = p.lock();
    // let _lock2 = p.lock();
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:26:38
   |
26 |         self._guard = Some(self.lock.lock().unwrap());
   |                                      ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 24:5...
  --> src/main.rs:24:5
   |
24 | /     fn lock(&mut self) {
25 | |         println!("process is locking");
26 | |         self._guard = Some(self.lock.lock().unwrap());
27 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:26:28
   |
26 |         self._guard = Some(self.lock.lock().unwrap());
   |                            ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 16:6...
  --> src/main.rs:16:6
   |
16 | impl<'a> Proc<'a> {
   |      ^^
note: ...so that the expression is assignable
  --> src/main.rs:26:23
   |
26 |         self._guard = Some(self.lock.lock().unwrap());
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: expected  `std::option::Option<std::sync::MutexGuard<'a, _>>`
              found  `std::option::Option<std::sync::MutexGuard<'_, _>>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0495`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

Hi, everyone! I want to integrate the Mutex and MutexGuard into a struct.
Basically, my goal is to let the struct Proc to handle the lock and its guard by itself.
I would like to acquire the lock in the scheduler thread and release the process's own thread, i.e., there is a context switch between these two operations.
That's the reason why I want to integrate the lock and its guard into the Proc struct.
Advanced thanks for the help and suggestion from you guys!

You are trying to create a self-referential type, where one of the fields references another. Rust doesn't support this pattern very well, and I would urge you to restructure your code to avoid this. One way around this is to use parking_lot's RawMutex which you can lock and unlock directly, no RAII guard required.

use parking_lot::{RawMutex, lock_api::RawMutex as _};

struct Proc {
    lock: RawMutex,
}

impl Proc {
    fn new() -> Self {
        Self {
            lock: RawMutex::INIT,
        }
    }
    
    fn lock(&mut self) {
        println!("process is locking");
        self.lock.lock();
    }
    
    fn unlock(&mut self) {
        println!("process is unlocking");
        self.lock.unlock();
    }
}
1 Like

I see. Seems like locking and unlocking directly would be better.
Thanks for your suggestion!

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.