gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 08:02:44 24 4
gpt4 key购买 nike

我读过 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 Resource Acquisition Is Initialization,其本意是变量构造函数一旦执行完毕,就获得了所需的资源,不处于半生不熟的状态,通常用于表示销毁所述变量将释放它拥有的任何资源。

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

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com