所以我正在追求我的 Rust 冒險(喜歡它)并且我正在探索執行緒。像往常一樣,我偶然發現了一個我不明白的錯誤。
這是一個最小的例子:
use std::thread;
pub fn compute_something(input: &Vec<&usize>) -> usize {
input.iter().map(|v| *v).sum()
}
pub fn main() {
let items = vec![0, 1, 2, 3, 4, 5];
let mut slice: Vec<&usize> = Vec::new();
slice.push(&items[1]); // borrowed value does not live long enough
// argument requires that `items` is borrowed for `'static`
slice.push(&items[2]); // borrowed value does not live long enough
// argument requires that `items` is borrowed for `'static`
assert_eq!(3, compute_something(&slice));
let h = thread::spawn(move || compute_something(&slice));
match h.join() {
Ok(result) => println!("Result: {:?}", result),
Err(e) => println!("Nope: {:?}", e)
}
} // `items` dropped here while still borrowed
我當然做了一個操場來說明。
如果我洗掉執行緒部分(該assert_eq!
行之后的所有內容)并呼叫compute_something(&slice)
它編譯得很好。
我在這里不明白三件事:
為什么在程式結束
items
時借用時丟棄是一個問題,運行時不應該清理記憶體嗎?這不像我將能夠訪問外部。slice
main
items
程式結束時還在借什么?slice
? 如果是這樣,為什么同一個程式只通過洗掉assert_eq!
行后的所有內容來編譯?我看不出它如何改變借貸模式。為什么
compute_something
從執行緒的閉包內部呼叫會產生問題,我該如何解決?
uj5u.com熱心網友回復:
你slice
進入你傳遞給的閉包thread::spawn()
。由于傳遞給的閉包thread::spawn()
must be 'static
,這意味著被移動到閉包中的向量不能借用任何不是的東西'static
。因此,編譯器推斷出slice
to的型別Vec<&'static usize>
。
但它確實借用了一些不是的東西'static
——你試圖推入它的值是從一個變數 local to 借用的main()
,所以編譯器會抱怨這一點。
解決這種情況的最簡單方法是擁有slice
aVec<usize>
并且根本不借用 from items
。
另一種選擇是使用crate中的作用域執行緒crossbeam
,它知道如何通過強制在作用域結束之前連接所有執行緒來安全地從區域變數中借用。
直接回答您提出的問題:
為什么在程式結束時借用時丟棄專案是一個問題,運行時不應該清理記憶體嗎?
當main()
終止時,所有執行緒也將終止——但是,有一個短暫的時間視窗,在此期間本地值main()
已被銷毀但在執行緒終止之前。在這個視窗中可能存在懸空參考,這違反了 Rust 的記憶體安全模型。這就是為什么thread::spawn()
需要'static
關閉。
即使您自己加入執行緒,借用檢查器也不知道加入執行緒會結束借用。(這是crossbeam
作用域執行緒解決的問題。)
items
程式結束時還在借什么?
移入閉包的向量仍在借用items
。
為什么
compute_something
從執行緒的閉包內部呼叫會產生問題,我該如何解決?
呼叫此函式不會產生問題。進入slice
關閉狀態正在制造問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/470141.html
下一篇:使消費者/生產者問題更高??級