rust - 非词汇生命周期借用检查器是否会过早释放锁定?

标签 rust mutex raii borrow-checker

我读过What are non-lexical lifetimes?。使用非词法借用检查器,可以编译以下代码:

fn main() {
    let mut scores = vec![1, 2, 3];
    let score = &scores[0]; // borrows `scores`, but never used
                            // its lifetime can end here

    scores.push(4);         // borrows `scores` mutably, and succeeds
}

在上述情况下,这似乎是合理的,但是当涉及到互斥锁时,我们不希望过早释放它。

在下面的代码中,我想首先锁定共享结构,然后执行关闭,主要是为了避免死锁。但是,我不确定该锁是否会过早释放。

use lazy_static::lazy_static; // 1.3.0
use std::sync::Mutex;

struct Something;

lazy_static! {
    static ref SHARED: Mutex<Something> = Mutex::new(Something);
}

pub fn lock_and_execute(f: Box<Fn()>) {
    let _locked = SHARED.lock(); // `_locked` is never used.
                                 // does its lifetime end here?
    f();
}

Rust是否会特别对待锁,以确保其使用生命周期可以延长到范围的尽头?我们是否必须像下面的代码那样显式地使用该变量,以避免过早丢失锁?

pub fn lock_and_execute(f: Box<Fn()>) {
    let locked = SHARED.lock(); // - lifetime begins
    f();                        // |
    drop(locked);               // - lifetime ends
}

最佳答案

这里有一个误解:NLL(非词法生存期)影响借位检查,而不影响对象的实际生存期。

Rust广泛使用RAII1,因此许多对象(例如锁)的Drop实现都有副作用,这些副作用必须在执行流程中确定且可预测的点上发生。

NLL不会更改此类对象的生存期,因此它们的析构函数在与之前完全相同的时间执行:在其词法作用域的末尾,以相反的创建顺序执行。

NLL确实改变了对使用期限以进行借阅检查的编译器的理解。实际上,这不会导致任何代码更改。这纯粹是分析。进行此分析更加巧妙,以更好地识别使用引用的实际范围:

  • 在NLL之前,从创建引用到删除引用都被视为“使用中”,通常是其词法范围(因此得名)。
  • NLL,而不是:
  • 如果可能,尝试推迟“使用中”跨度的开始。
  • 以引用的最后使用结束“使用中”跨度。

  • 如果是Ref<'a>(来自RefCell),则Ref<'a>将在词法作用域的末尾删除,此时它将使用对RefCell的引用来减少计数器。

    NLL不会剥离抽象层,因此必须考虑到任何包含引用的对象(例如Ref<'a>)都可以在其Drop实现中访问该引用。结果,任何包含引用的对象(例如锁)都将强制NLL认为引用的“使用中”范围会一直扩展到被丢弃为止。

    1资源获取是初始化,其原始含义是,一旦执行了变量构造函数,它便获取了所需的资源,并且未处于半熟状态,这通常用来表示该变量的破坏将被释放。它拥有的任何资源。

    关于rust - 非词汇生命周期借用检查器是否会过早释放锁定?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63122567/

    相关文章:

    regex - Rust 正则表达式模式 - 无法识别的转义模式

    rust - 我怎样才能检测到错误而不是让这个 Rust 程序中止?

    asynchronous - 在实践中实现Future时如何使用Context和Wakers

    c++ - 包含互斥 C++ 时的套接字问题

    c++ - 如何在互斥锁中优先考虑特权线程?

    go - Go中的二级缓存(内存+redis)实现

    c++ - 是否有适合 'ownership-in-a-package' 的 'handles' 可用?

    c++ - 如何将 C API 封装到 RAII C++ 类中?

    reference - 为什么我可以将不可变引用传递给 BufReader,而不是可变引用?

    inversion-of-control - 控制反转和RAII可以一起玩吗?