【问题标题】:When would you use a Mutex without an Arc?什么时候使用没有 Arc 的 Mutex?
【发布时间】:2015-10-14 03:51:18
【问题描述】:

Rust 中一个极其常见的模式是Arc<Mutex<T>>,其中Arc 提供内存管理,Mutex 提供对资源的安全多线程访问。还有什么可以用来代替Arc,在什么情况下?

【问题讨论】:

    标签: rust


    【解决方案1】:

    Arc 在这种情况下当然是最常见的,但还有其他指针类型允许共享。主要的(也是最常见的,在 Rust 的其余部分中)一个是共享引用 &T。这通常不适用于std::thread::spawn'd 线程,因为它通常指向由其他线程控制的数据,因此通常不是'static(特别是当它是&Mutex<T> 时)。但是,可以使用scoped thread 创建一个可以与其父级共享数据的线程。例如

    use crossbeam; // 0.7.3
    use std::sync::Mutex;
    
    fn main() {
        let data = Mutex::new(vec![0, 1]);
    
        crossbeam::scope(|scope| {
            // these run concurrently:
            let _guard = scope.spawn(|_| {
                data.lock().unwrap().push(2);
            });
            data.lock().unwrap().push(3);
        })
        .unwrap();
    
        println!("{:?}", data.lock().unwrap());
        // one of [0, 1, 2, 3] or [0, 1, 3, 2]
    }
    

    传递给scope.spawn 的闭包中data 的类型实际上是&Mutex<Vec<i32>>(因为它没有move 关键字,所以闭包使用默认捕获样式:通过引用)。

    &Arc 是可以在标准库/语言中实现这种线程安全共享的两个,但也可以编写在外部库中提供线程安全共享的指针类型。

    但是,远离Pointer<Mutex<...>> 模式,将互斥体和共享区分开会很有用,例如Arc<Vec<Mutex<T>>> 允许一个人共享一定数量的Mutex<T>,而不必单独Arc,或者可能想对Mutex 进行一些抽象,因此将其包装在struct 中:

    struct Wrapped {
        data: Mutex<T>,
    }
    impl Wrapped {
        // fancy methods that abstract over `data.lock()`
    }
    

    然后可能会看到Arc&lt;Wrapped&gt;(或其他一些允许共享的指针)。

    【讨论】:

    • 是否有可能以某种方式在没有 Arc 的情况下使用带有 thread::spawn 的 Mutex,或者我需要编写自己的包装器?在 C/C++ 中,我不需要引用计数开销来在线程内使用互斥锁。
    • @NN_ C/C++ 编译器没有生命周期的概念(除了 Herb Sutter 的用于 MSVC 和 Clang 的可选 C++ 生命周期检查器),因此您可以做任何您喜欢的潜在的有趣的事情。 Rust 曾经有作用域线程,但实现有一个生命周期的错误,所以它被废弃了。 Crossbeam 通过围绕创建 WaitGroup(类似于屏障)的作用域线程创建作用域来解决生命周期问题,将 WaitGroup 克隆到每个线程中,然后等待对 WaitGroup 的所有引用被删除。如果您坚持,您可以复制 Crossbeam 的解决方案而不实施终身安全。
    猜你喜欢
    • 1970-01-01
    • 2021-02-23
    • 2021-11-12
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 2019-10-27
    • 2021-09-09
    • 1970-01-01
    相关资源
    最近更新 更多