我正在尝试编写一个程序,其中一个线程写入队列,另一个线程从队列中读取
但是我遇到了一个关于在读取队列的线程中访问“队列”的问题
下面是未编译的代码
use ::std::collections::VecDeque;
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
use std::cell::RefCell;
use std::path::{Path, PathBuf};
use std::thread;
use std::time::Duration;
fn main() {
//let path = std::env::args()
// .nth(1)
// .expect("Argument 1 needs to be a path");
//println!("watching {}", path);
let path = "c:\\testfolder";
if let Err(e) = watch(path) {
println!("error: {:?}", e)
}
}
fn process_queue(queue: &VecDeque<String>) -> () {}
fn watch<P: AsRef<Path>>(path: P) -> notify::Result<()> {
let (tx, rx) = std::sync::mpsc::channel();
// Automatically select the best implementation for your platform.
// You can also access each implementation directly e.g. INotifyWatcher.
let mut watcher = RecommendedWatcher::new(tx, Config::default())?;
// Add a path to be watched. All files and directories at that path and
// below will be monitored for changes.
let mut queue: VecDeque<String> = VecDeque::new();
thread::spawn(|| {
// everything in here runs
process_queue(&queue)
});
watcher.watch(path.as_ref(), RecursiveMode::Recursive)?;
for res in rx {
match res {
Ok(event) => {
println!("changed: {:?}", event.paths);
let os_str: String = String::from(event.paths[0].to_str().unwrap());
//let my_str: String = os_str.unwrap().to_str().unwrap();
//let s =os_str.into_os_string();
queue.push_back(os_str);
}
Err(e) => println!("watch error: {:?}", e),
}
}
Ok(())
}
Rust编译器的输出
error[E0373]: closure may outlive the current function, but it borrows `queue`, which is owned by the current function
--> src\main.rs:43:19
|
43 | thread::spawn(|| {
| ^^ may outlive borrowed value `queue`
...
47 | process_queue(&queue)
| ----- `queue` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src\main.rs:43:5
|
43 | / thread::spawn(|| {
44 | |
45 | | // everything in here runs
46 | |
47 | | process_queue(&queue)
48 | |
49 | | });
| |______^
help: to force the closure to take ownership of `queue` (and any other referenced variables), use the `move` keyword
|
43 | thread::spawn(move || {
| ++++
error[E0502]: cannot borrow `queue` as mutable because it is also borrowed as immutable
--> src\main.rs:63:17
|
43 | thread::spawn(|| {
| - -- immutable borrow occurs here
| _____|
| |
44 | |
45 | | // everything in here runs
46 | |
47 | | process_queue(&queue)
| | ----- first borrow occurs due to use of `queue` in closure
48 | |
49 | | });
| |______- argument requires that `queue` is borrowed for `'static`
...
63 | queue.push_back(os_str);
| ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
从错误中我了解到编译器不允许同时使用可变和不可变引用。
但我不知道如何实现我试图用这些限制做的事情。
4条答案
按热度按时间sbtkgmzw1#
解决这个问题的一种方法是
Box
-ingVecDeque
,这样就可以将一个克隆的引用传递给process_queue
函数。使用Box允许您在堆上分配
VecDeque
,以便您可以为派生的线程提供对Vec的引用,并且仍然可以在当前线程中改变队列。这看起来像:
并且可以更新
process_queue
以接受正确的类型:请注意,使用这种实现,
process_queue
只在线程产生时运行一次,如果您希望process_queue在每次队列更改时执行某些操作,则遵循其他人的建议,使用类似Channels这样的语句是最有意义的。icnyk63a2#
感谢您的所有回复
从所有的响应中,我了解到使用通道并将接收器循环移动到其他线程(如user4815162342所建议的)将是最好的解决方案
332nm8kg3#
根据您的建议,我使用渠道成功地实现了我所要做的事情。
最终工作代码粘贴在下面
bt1cpqcv4#
在您的情况下,使用Rust的MPSC(多生产者单消费者,即本质上是一个队列)可能是最好的。您也可以使用
Arc
和Mutex
结构体创建一个在多个线程之间共享的变量,但这会过度使用,并可能会影响性能(任何时候只有一个线程可以访问该变量)。下面是一个多线程MPSC的示例,我将让您根据您的基础架构对其进行调整: