gpt4 book ai didi

multithreading - 在其他线程内部生成线程时借用的问题

转载 作者:行者123 更新时间:2023-12-03 11:41:01 24 4
gpt4 key购买 nike

我已阅读以下问题:
How can I run a set of functions on a recurring interval without running the same function at the same time using only the standard Rust library?
并阐述了一些更复杂的测试。
以下代码为函数添加了&str参数,并且可以正常工作:

use std::{
thread,
time::{Duration, Instant},
};

fn main() {
let scheduler = thread::spawn(|| {
let wait_time = Duration::from_millis(500);

let one: &str = "Alpha";
let two: &str = "Beta";

// Make this an infinite loop
// Or some control path to exit the loop
for _ in 0..5 {
let start = Instant::now();
eprintln!("Scheduler starting at {:?}", start);

let thread_a = thread::spawn(move || { a(&one) });
let thread_b = thread::spawn(move || { b(&two) });

thread_a.join().expect("Thread A panicked");
thread_b.join().expect("Thread B panicked");

let runtime = start.elapsed();

if let Some(remaining) = wait_time.checked_sub(runtime) {
eprintln!(
"schedule slice has time left over; sleeping for {:?}",
remaining
);
thread::sleep(remaining);
}
}
});

scheduler.join().expect("Scheduler panicked");
}

fn a(a: &str) {
eprintln!("{}", a);
thread::sleep(Duration::from_millis(100))
}
fn b(b: &str) {
eprintln!("{}", b);
thread::sleep(Duration::from_millis(200))
}
我的理解是,这是有效的,因为为str实现了复制特性。
现在考虑以下示例:
use std::{
thread,
time::{Duration, Instant},
};

fn main() {
let scheduler = thread::spawn(|| {
let wait_time = Duration::from_millis(500);

let one: String = String::from("Alpha");
let two: String = String::from("Beta");

// Make this an infinite loop
// Or some control path to exit the loop
for _ in 0..5 {
let start = Instant::now();
eprintln!("Scheduler starting at {:?}", start);

let thread_a = thread::spawn(move || { a(&one) });
let thread_b = thread::spawn(move || { b(&two) });

thread_a.join().expect("Thread A panicked");
thread_b.join().expect("Thread B panicked");

let runtime = start.elapsed();

if let Some(remaining) = wait_time.checked_sub(runtime) {
eprintln!(
"schedule slice has time left over; sleeping for {:?}",
remaining
);
thread::sleep(remaining);
}
}
});

scheduler.join().expect("Scheduler panicked");
}

fn a(a: &str) {
eprintln!("{}", a);
thread::sleep(Duration::from_millis(100))
}
fn b(b: &str) {
eprintln!("{}", b);
thread::sleep(Duration::from_millis(200))
}
我在编译时得到这个:
error[E0382]: use of moved value: `one`
--> src\main.rs:19:42
|
10 | let one: String = String::from("Alpha");
| --- move occurs because `one` has type `String`, which does not implement the `Copy` trait
...
19 | let thread_a = thread::spawn(move || { a(&one) });
| ^^^^^^^ --- use occurs due to use in closure
| |
| value moved into closure here, in previous iteration of loop

error[E0382]: use of moved value: `two`
--> src\main.rs:20:42
|
11 | let two: String = String::from("Beta");
| --- move occurs because `two` has type `String`, which does not implement the `Copy` trait
...
20 | let thread_b = thread::spawn(move || { b(&two) });
| ^^^^^^^ --- use occurs due to use in closure
| |
| value moved into closure here, in previous iteration of loop

error: aborting due to 2 previous errors
EDIT1
似乎可以使用.clone()解决
但是现在考虑以下代码:
use std::{
thread,
time::{Duration, Instant},
};

fn main() {

let one: String = String::from("Alpha");
let two: String = String::from("Beta");

let scheduler = thread::spawn(|| {
let wait_time = Duration::from_millis(500);

// Make this an infinite loop
// Or some control path to exit the loop
for _ in 0..5 {
let start = Instant::now();
eprintln!("Scheduler starting at {:?}", start);

let one = one.clone();
let two = two.clone();

let thread_a = thread::spawn(move || { a(&one) });
let thread_b = thread::spawn(move || { b(&two) });

thread_a.join().expect("Thread A panicked");
thread_b.join().expect("Thread B panicked");

let runtime = start.elapsed();

if let Some(remaining) = wait_time.checked_sub(runtime) {
eprintln!(
"schedule slice has time left over; sleeping for {:?}",
remaining
);
thread::sleep(remaining);
}
}
});

scheduler.join().expect("Scheduler panicked");
}

fn a(a: &str) {
eprintln!("{}", a);
thread::sleep(Duration::from_millis(100))
}
fn b(b: &str) {
eprintln!("{}", b);
thread::sleep(Duration::from_millis(200))
}
我现在得到不同的错误代码:
error[E0373]: closure may outlive the current function, but it borrows `two`, which is owned by the current function
--> src\main.rs:11:35
|
11 | let scheduler = thread::spawn(|| {
| ^^ may outlive borrowed value `two`
...
21 | let two = two.clone();
| --- `two` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src\main.rs:11:21
|
11 | let scheduler = thread::spawn(|| {
| _____________________^
12 | | let wait_time = Duration::from_millis(500);
13 | |
14 | | // Make this an infinite loop
... |
38 | | }
39 | | });
| |______^
help: to force the closure to take ownership of `two` (and any other referenced variables), use the `move` keyword
|
11 | let scheduler = thread::spawn(move || {
| ^^^^^^^

error[E0373]: closure may outlive the current function, but it borrows `one`, which is owned by the current function
--> src\main.rs:11:35
|
11 | let scheduler = thread::spawn(|| {
| ^^ may outlive borrowed value `one`
...
20 | let one = one.clone();
| --- `one` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src\main.rs:11:21
|
11 | let scheduler = thread::spawn(|| {
| _____________________^
12 | | let wait_time = Duration::from_millis(500);
13 | |
14 | | // Make this an infinite loop
... |
38 | | }
39 | | });
| |______^
help: to force the closure to take ownership of `one` (and any other referenced variables), use the `move` keyword
|
11 | let scheduler = thread::spawn(move || {
| ^^^^^^^

error: aborting due to 2 previous errorsù

最佳答案

为简洁起见,我只提及one,但two也是如此。 thread::spawn(move || { a(&one) })的问题在于,将one移至闭包中,然后会导致编译错误,因为one在下一次迭代中不再可用。
预先借用&one也不起作用,因为借用one的线程可能会超出外部线程的生命周期。为了使其正常工作,您可以在生成线程之前克隆one(和two)。

let one = one.clone();
let two = two.clone();

let thread_a = thread::spawn(move || a(&one));
let thread_b = thread::spawn(move || b(&two));

或者,如果您真的想借用它,而不克隆它。然后您可以使用例如 crossbeam 和生成线程的作用域。另请参见 "How can I pass a reference to a stack variable to a thread?"
...

let one: String = String::from("Alpha");
let two: String = String::from("Beta");

let one = &one;
let two = &two;

crossbeam::scope(|scope| {
// Make this an infinite loop
// Or some control path to exit the loop
for _ in 0..5 {
let start = Instant::now();
eprintln!("Scheduler starting at {:?}", start);

let thread_a = scope.spawn(move |_| a(&one));
let thread_b = scope.spawn(move |_| b(&two));

thread_a.join().expect("Thread A panicked");
thread_b.join().expect("Thread B panicked");

let runtime = start.elapsed();

if let Some(remaining) = wait_time.checked_sub(runtime) {
eprintln!(
"schedule slice has time left over; sleeping for {:?}",
remaining
);
thread::sleep(remaining);
}
}
})
.unwrap();

关于multithreading - 在其他线程内部生成线程时借用的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65275117/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com