Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mutex<bool> with an atomic read&write

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.

like image 244
at54321 Avatar asked Dec 14 '22 06:12

at54321


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

like image 95
user4815162342 Avatar answered Dec 27 '22 17:12

user4815162342


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.

like image 39
lkolbly Avatar answered Dec 27 '22 18:12

lkolbly