关于Rust中thread::scope闭包未借用Mutex变量的技术疑问
问题解答
先贴出对应的代码:
use std::thread; use std::sync::Mutex; use std::collections::VecDeque; use std::time::Duration; fn main() { let queue = Mutex::new(VecDeque::new()); thread::scope(|s| { let t = s.spawn(|| { loop { let item = queue.lock().unwrap().pop_front(); if let Some(item) = item { dbg!(item); } else { thread::park(); } } }); for i in 1.. { queue.lock().unwrap().push_back(i); t.thread().unpark(); thread::sleep(Duration::from_secs(1)); }; }); }
核心解释
闭包确实借用了
queue,但只是不可变共享引用
子线程的闭包捕获的是&Mutex<VecDeque<_>>,也就是queue的不可变引用。因为Mutex的lock方法是定义在&self上的(只需要不可变引用就能调用),通过锁提供的内部可变性(MutexGuard会授予内部数据的可变访问权),我们依然能修改内部的VecDeque,不需要对queue本身进行可变借用。Rust借用规则允许多个不可变引用共存
主线程的for循环里同样是获取queue的不可变引用来调用lock,这和子线程的不可变引用完全兼容——只要不同时存在可变引用,Rust就不会报错。Mutex自身的互斥机制会保证同一时间只有一个线程能拿到内部数据的可变访问,这和Rust的借用规则形成互补。thread::scope是关键前提
普通的thread::spawn不允许捕获栈变量的引用,因为编译器无法保证子线程不会比变量活得久。但thread::scope会强制所有子线程在scope闭包执行完毕前退出,所以编译器能安全地允许闭包捕获栈上变量的引用,不需要把queue包装成Arc这类智能指针。
内容的提问来源于stack exchange,提问作者Vishakh Prakash
相关产品推荐
相关产品推荐

