Token Types with Data: Mutex Guards

Sometimes, a token type needs additional data. A mutex guard is an example of a token that represents permission + data.

use std::sync::{Arc, Mutex, MutexGuard};

fn main() {
    let mutex = Arc::new(Mutex::new(42));
    let try_mutex_guard: Result<MutexGuard<'_, _>, _> = mutex.lock();
    if let Ok(mut guarded) = try_mutex_guard {
        // The acquired MutexGuard is proof of exclusive access.
        *guarded = 451;
    }
}
  • Mutexes enforce mutual exclusion of read/write access to a value. We’ve covered Mutexes earlier in this course already (See: RAII/Mutex), but here we’re looking at MutexGuard specifically.

  • MutexGuard is a value generated by a Mutex that proves you have read/write access at that point in time.

    MutexGuard also holds onto a reference to the Mutex that generated it, with Deref and DerefMut implementations that give access to the data of Mutex while the underlying Mutex keeps that data private from the user.

  • If mutex.lock() does not return a MutexGuard, you don’t have permission to change the value within the mutex.

    Not only do you have no permission, but you have no means to access the mutex data unless you gain a MutexGuard.

    This contrasts with C++, where mutexes and lock guards do not control access to the data itself, acting only as a flag that a user must remember to check every time they read or manipulate data.

  • Demonstrate: make the mutex variable mutable then try to dereference it to change its value. Show how there’s no deref implementation for it, and no other way to get to the data held by it other than getting a mutex guard.