我如何改变线程的结构?



请帮帮我,我完全糊涂了。

我如何使这段代码工作?

我需要改变线程中的结构成员…

#[derive(Debug)]
struct S {
str: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
str: "a".to_string(),
b: false,
i: 0,
});
let mut threads = vec![];
for s in vec_s {
{
let mut _s = &s;
threads.push(std::thread::spawn(move || {
_s.b = true;
_s.str = "b".to_string();
_s.i = 1;
}));
}
}
for thread in threads {
let _ = thread.join();
}
dbg!(&vec_s);
}

编译器输出大量错误:

error[E0594]: cannot assign to `_s.b`, which is behind a `&` reference
--> src/main.rs:23:17
|
23 |                 _s.b = true;
|                 ^^^^^^^^^^^ cannot assign
error[E0594]: cannot assign to `_s.str`, which is behind a `&` reference
--> src/main.rs:24:17
|
24 |                 _s.str = "b".to_string();
|                 ^^^^^^ cannot assign
error[E0594]: cannot assign to `_s.i`, which is behind a `&` reference
--> src/main.rs:25:17
|
25 |                 _s.i = 1;
|                 ^^^^^^^^ cannot assign
error[E0597]: `s` does not live long enough
--> src/main.rs:21:26
|
21 |               let mut _s = &s;
|                            ^^ borrowed value does not live long enough
22 |               threads.push(std::thread::spawn(move || {
|  __________________________-
23 | |                 _s.b = true;
24 | |                 _s.str = "b".to_string();
25 | |                 _s.i = 1;
26 | |             }));
| |______________- argument requires that `s` is borrowed for `'static`
27 |           }
28 |       }
|       - `s` dropped here while still borrowed
error[E0382]: borrow of moved value: `vec_s`
--> src/main.rs:34:10
|
9   |     let mut vec_s = vec![];
|         --------- move occurs because `vec_s` has type `Vec<S>`, which does not implement the `Copy` trait
...
19  |     for s in vec_s {
|              ----- `vec_s` moved due to this implicit call to `.into_iter()`
...
34  |     dbg!(&vec_s);
|          ^^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `vec_s`
--> /home/martin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:261:18
|
261 |     fn into_iter(self) -> Self::IntoIter;
|                  ^^^^
help: consider iterating over a slice of the `Vec<S>`'s content to avoid moving into the `for` loop
|
19  |     for s in &vec_s {
|              +

您正在尝试执行多线程。多线程访问的所有内容都必须是线程安全的。此外,Rust非常严格(零未定义行为容忍),编译器必须理解你的代码是线程安全的。

这里最大的问题是Rust的借用检查器不理解你的线程在某个点被连接。因此,它不允许您创建对S对象的引用,因为它无法证明这些引用存在了多长时间。Rust必须能够证明它们在你的S对象被丢弃之前被销毁;这是Rust的borrow checker安全保证的一部分。

对于特定的用例,Rust引入了线程作用域。有了它们,编译器最终可以理解线程的生存期。

修复了一些次要的所有权问题(使用&mut vec_s为循环,否则vec_s对象被循环消耗),现在可以工作了:

#[derive(Debug)]
struct S {
s: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
s: "a".to_string(),
b: false,
i: 0,
});
std::thread::scope(|scope| {
let mut threads = vec![];
for s in &mut vec_s {
threads.push(scope.spawn(move || {
s.b = true;
s.s = "b".to_string();
s.i = 1;
}));
}
for thread in threads {
let _ = thread.join();
}
});
dbg!(&vec_s);
}
[src/main.rs:31] &vec_s = [
S {
s: "b",
b: true,
i: 1,
},
]

另一个优化:

如果您不实际使用JoinHandles进行错误传播或类似操作,那么在本例中根本不需要它们。scope已经自动连接它在作用域结束时产生的所有线程:

#[derive(Debug)]
struct S {
s: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
s: "a".to_string(),
b: false,
i: 0,
});
std::thread::scope(|scope| {
for s in &mut vec_s {
scope.spawn(move || {
s.b = true;
s.s = "b".to_string();
s.i = 1;
});
}
});
dbg!(&vec_s);
}
[src/main.rs:27] &vec_s = [
S {
s: "b",
b: true,
i: 1,
},
]

最新更新