【问题标题】:Mutex<bool> with an atomic read&write具有原子读写的 Mutex<bool>
【发布时间】:2021-11-02 19:01:37
【问题描述】:

我需要一个可以被多个线程访问的全局布尔标志。

这是我需要的示例:

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
}

get_flag_and_set_to_true() 的实现感觉不太对劲。我想最好只锁一次。最好的方法是什么?

顺便说一句,我想Arc&lt;[AtomicBool]&gt; 也可以使用,理论上应该更快,尽管在我的特定情况下,速度优势并不明显。

【问题讨论】:

  • 只是将GLOBAL_FLAG.lock().unwrap() 存储在变量中?当它在函数结束时消失时,锁将被释放

标签: rust concurrency mutex


【解决方案1】:

可以想象,当您读取GLOBAL_FLAG 和将GLOBAL_FLAG 设置为true 时,可能会出现另一个线程。要解决此问题,您可以直接存储 GLOBAL_FLAG.lock().unwrap() 返回的 MutexGuard (docs):

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 将保持互斥锁锁定,直到它被删除。

【讨论】:

    【解决方案2】:

    顺便说一句,我想Arc&lt;[AtomicBool]&gt; 也可以使用,理论上应该更快,尽管在我的特定情况下,速度优势并不明显。

    这不仅关乎性能方面的好处,还关乎代码量和推理代码的易用性。使用AtomicBool,您不需要SyncLazy 或互斥体,代码更短更清晰:

    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

    【讨论】:

    • “易于推理代码”之类的 Ordering 很简单“确实,这个模型非常复杂,而且已知有几个缺陷。” doc.rust-lang.org/nomicon/atomics.html
    • @Stargateur 当您需要使用它来同步其他不安全的数据结构时,这很复杂。在这种情况下,相比Mutex,确实很简单。
    • 感谢您的有用回答。事实上,AtomicBoolean 更简单。我以为我仍然需要处理SyncLazyArc 之类的东西,但显然不需要。
    • @user4815162342 事情是 3 人说服原子是你的简单原因。错误信息很糟糕youtu.be/ZQFzMfHIxng
    • @Stargateur 此答案中没有错误信息,您的指控在现实中没有任何根据或依据。正如我之前所说,当类型提供的原子操作(并通过编译器内在函数实现)完美地映射到代码需要执行的操作时,原子操作很简单,就像 OP 的情况一样。是的,将原子与其他数据加载结合起来很复杂,但一般来说,互斥锁、rwlock、条件变量和并行编程也是如此。这不是避免标准库提供的完全安全的 API 的理由。
    猜你喜欢
    • 2010-09-08
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-25
    相关资源
    最近更新 更多