Mutex<bool> with an atomic read&write

Viewed 488

I need to have a global boolean flag that will be accessed by multiple threads.

Here is an example of what I need:

static GLOBAL_FLAG: SyncLazy<Mutex<bool>> = SyncLazy::new(|| {
    Mutex::new(false)
});

fn set_flag_to_true() {  // can be called by 2+ threads concurrently 
    *GLOBAL_FLAG.lock().unwrap() = true;
}

fn get_flag_and_set_to_true() -> bool {  // only one thread is calling this function
    let v = *GLOBAL_FLAG.lock().unwrap();  // Obtain current flag value
    *GLOBAL_FLAG.lock().unwrap() = true;  // Always set the flag to true
    v  // Return the previous value
}

The get_flag_and_set_to_true() implementation doesn't feel quite right. I imagine it would be best if I only locked once. What's the best way to do that?

BTW I suppose Arc<[AtomicBool]> can also be used and should in theory be faster, although in my particular case the speed benefit will be unnoticeable.

2 Answers

BTW I suppose Arc<[AtomicBool]> can also be used and should in theory be faster, although in my particular case the speed benefit will be unnoticeable.

It's not just about benefit in performance, but also in amount of code and ease of reasoning about the code. With AtomicBool you don't need either SyncLazy or the mutex, and the code is shorter and clearer:

use std::sync::atomic::{AtomicBool, Ordering};

static GLOBAL_FLAG: AtomicBool = AtomicBool::new(false);

pub fn set_flag_to_true() {
    GLOBAL_FLAG.store(true, Ordering::SeqCst);
}

pub fn get_flag_and_set_to_true() -> bool {
    GLOBAL_FLAG.swap(true, Ordering::SeqCst)
}

Playground

Conceivably, another thread could come in between when you read GLOBAL_FLAG and when you set GLOBAL_FLAG to true. To work around this you can directly store the MutexGuard (docs) that GLOBAL_FLAG.lock().unwrap() returns:

fn get_flag_and_set_to_true() -> bool {  // only one thread is calling this function
    let mut global_flag = GLOBAL_FLAG.lock().unwrap();
    let v = *global_flag;  // Obtain current flag value
    *global_flag = true;  // Always set the flag to true
    v  // Return the previous value
}

global_flag will keep the mutex locked until it gets dropped.

Related