在循环中借用可变变量
Borrow mutable in a loop
我尝试处理具有多个工作线程的数组,就像 Rayon 的 par_iter()
函数一样,但我想要一个可变引用 target
,每个线程一个。
我有一个像这样的简单函数
pub fn parallel_map_vector<A:Sync,T:Send,B:Send>(a:&[A], t:&mut [T], b:&mut [B], f:impl Fn(&A,&mut T)+Send+Sync){
assert_eq!(a.len(),b.len());
let atomic_counter = AtomicUsize::new(0);
crossbeam::scope(|scope| {
for target in t {
scope.spawn( |_| {
loop {
let idx = atomic_counter.fetch_add(1, Ordering::Relaxed);
if idx < a.len() {unsafe{std::slice::from_raw_parts_mut(b,b_len)};
f(&a[idx], target)
}else{
break
}
}
});
}
}).unwrap();
}
出于某种原因,我一直收到错误消息
error[E0373]: closure may outlive the current function, but it borrows `target`, which is owned by the current function
--> htm/src/parallel.rs:11:26
|
9 | crossbeam::scope(|scope| {
| ----- has type `&crossbeam::thread::Scope<'1>`
10 | for target in t {
11 | scope.spawn( |_| {
| ^^^ may outlive borrowed value `target`
...
17 | f(&a[idx], target)
| ------ `target` is borrowed here
|
note: function requires argument type to outlive `'1`
--> htm/src/parallel.rs:11:13
|
11 | / scope.spawn( |_| {
12 | | loop {
13 | | let idx = atomic_counter.fetch_add(1, Ordering::Relaxed);
14 | | if idx < a.len() {
... |
21 | | }
22 | | });
| |______________^
help: to force the closure to take ownership of `target` (and any other referenced variables), use the `move` keyword
|
11 | scope.spawn( move |_| {
但是当我在 rust playground 中尝试它时,它编译没有问题
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0a10cbfd2f135975f4682c843664d539
这里有什么问题?该代码对我来说看起来很安全。
您链接到的游乐场示例使用的是 2021 版 Rust,它允许 disjoint capture in closures (and hence the closure for each thread captures only target
rather than the entire t
slice). If you switch to the 2018 edition,它会产生与您的问题相同的错误。
在 Cargo.toml
中指定您需要 2021 版(需要 rustc >= 1.56.0)。
我尝试处理具有多个工作线程的数组,就像 Rayon 的 par_iter()
函数一样,但我想要一个可变引用 target
,每个线程一个。
我有一个像这样的简单函数
pub fn parallel_map_vector<A:Sync,T:Send,B:Send>(a:&[A], t:&mut [T], b:&mut [B], f:impl Fn(&A,&mut T)+Send+Sync){
assert_eq!(a.len(),b.len());
let atomic_counter = AtomicUsize::new(0);
crossbeam::scope(|scope| {
for target in t {
scope.spawn( |_| {
loop {
let idx = atomic_counter.fetch_add(1, Ordering::Relaxed);
if idx < a.len() {unsafe{std::slice::from_raw_parts_mut(b,b_len)};
f(&a[idx], target)
}else{
break
}
}
});
}
}).unwrap();
}
出于某种原因,我一直收到错误消息
error[E0373]: closure may outlive the current function, but it borrows `target`, which is owned by the current function
--> htm/src/parallel.rs:11:26
|
9 | crossbeam::scope(|scope| {
| ----- has type `&crossbeam::thread::Scope<'1>`
10 | for target in t {
11 | scope.spawn( |_| {
| ^^^ may outlive borrowed value `target`
...
17 | f(&a[idx], target)
| ------ `target` is borrowed here
|
note: function requires argument type to outlive `'1`
--> htm/src/parallel.rs:11:13
|
11 | / scope.spawn( |_| {
12 | | loop {
13 | | let idx = atomic_counter.fetch_add(1, Ordering::Relaxed);
14 | | if idx < a.len() {
... |
21 | | }
22 | | });
| |______________^
help: to force the closure to take ownership of `target` (and any other referenced variables), use the `move` keyword
|
11 | scope.spawn( move |_| {
但是当我在 rust playground 中尝试它时,它编译没有问题 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0a10cbfd2f135975f4682c843664d539 这里有什么问题?该代码对我来说看起来很安全。
您链接到的游乐场示例使用的是 2021 版 Rust,它允许 disjoint capture in closures (and hence the closure for each thread captures only target
rather than the entire t
slice). If you switch to the 2018 edition,它会产生与您的问题相同的错误。
在 Cargo.toml
中指定您需要 2021 版(需要 rustc >= 1.56.0)。