Multithreading 如何从另一个螺纹终止或挂起生锈的螺纹?
编者按-此示例是在Rust 1.0之前创建的,此后特定类型已更改或删除。一般问题和概念仍然有效 我已经产生了一个线程,里面有一个无限循环和计时器Multithreading 如何从另一个螺纹终止或挂起生锈的螺纹?,multithreading,rust,Multithreading,Rust,编者按-此示例是在Rust 1.0之前创建的,此后特定类型已更改或删除。一般问题和概念仍然有效 我已经产生了一个线程,里面有一个无限循环和计时器 thread::spawn(|| { let mut timer = Timer::new().unwrap(); let periodic = timer.periodic(Duration::milliseconds(200)); loop { periodic.recv(); // Do
thread::spawn(|| {
let mut timer = Timer::new().unwrap();
let periodic = timer.periodic(Duration::milliseconds(200));
loop {
periodic.recv();
// Do my work here
}
});
基于某些条件,经过一段时间后,我需要从程序的另一部分终止此线程。换句话说,我想退出无限循环。如何才能正确地执行此操作?此外,我如何暂停此线程并在以后继续
我尝试使用全局不安全标志来中断循环,但我认为这个解决方案看起来不太好。对于终止和挂起线程,您可以使用通道 外部终止 在worker循环的每次迭代中,我们检查是否有人通过通道通知我们。如果是,或者通道的另一端超出范围,我们将中断循环
use std::io::{self, BufRead};
use std::sync::mpsc::{self, TryRecvError};
use std::thread;
use std::time::Duration;
fn main() {
println!("Press enter to terminate the child thread");
let (tx, rx) = mpsc::channel();
thread::spawn(move || loop {
println!("Working...");
thread::sleep(Duration::from_millis(500));
match rx.try_recv() {
Ok(_) | Err(TryRecvError::Disconnected) => {
println!("Terminating.");
break;
}
Err(TryRecvError::Empty) => {}
}
});
let mut line = String::new();
let stdin = io::stdin();
let _ = stdin.lock().read_line(&mut line);
let _ = tx.send(());
}
use std::io::{self, BufRead};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
println!("Press enter to wake up the child thread");
let (tx, rx) = mpsc::channel();
thread::spawn(move || loop {
println!("Suspending...");
match rx.recv() {
Ok(_) => {
println!("Working...");
thread::sleep(Duration::from_millis(500));
}
Err(_) => {
println!("Terminating.");
break;
}
}
});
let mut line = String::new();
let stdin = io::stdin();
for _ in 0..4 {
let _ = stdin.lock().read_line(&mut line);
let _ = tx.send(());
}
}
暂停和恢复
我们使用recv()
,它挂起线程,直到有东西到达通道。为了恢复线程,您需要通过通道发送一些内容;在这种情况下,单位值为()
。如果信道的传输端被丢弃,recv()
将返回Err(())
-我们使用它退出循环
use std::io::{self, BufRead};
use std::sync::mpsc::{self, TryRecvError};
use std::thread;
use std::time::Duration;
fn main() {
println!("Press enter to terminate the child thread");
let (tx, rx) = mpsc::channel();
thread::spawn(move || loop {
println!("Working...");
thread::sleep(Duration::from_millis(500));
match rx.try_recv() {
Ok(_) | Err(TryRecvError::Disconnected) => {
println!("Terminating.");
break;
}
Err(TryRecvError::Empty) => {}
}
});
let mut line = String::new();
let stdin = io::stdin();
let _ = stdin.lock().read_line(&mut line);
let _ = tx.send(());
}
use std::io::{self, BufRead};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
println!("Press enter to wake up the child thread");
let (tx, rx) = mpsc::channel();
thread::spawn(move || loop {
println!("Suspending...");
match rx.recv() {
Ok(_) => {
println!("Working...");
thread::sleep(Duration::from_millis(500));
}
Err(_) => {
println!("Terminating.");
break;
}
}
});
let mut line = String::new();
let stdin = io::stdin();
for _ in 0..4 {
let _ = stdin.lock().read_line(&mut line);
let _ = tx.send(());
}
}
其他工具
渠道是完成这些任务最简单、最自然(IMO)的方式,但不是最有效的方式。您可以在模块中找到其他并发原语。它们属于比通道更低的级别,但在特定任务中效率更高 理想的解决方案是a。您可以在
std::sync模块中使用,如下所示
这是文档中的示例:
我自己已经多次回过这个问题,下面是我认为能够解决OP的意图和其他人让线程停止自身的最佳实践的内容。基于公认的答案,这是对mpsc的一个很好的升级,允许克隆和移动消息端点。它还具有方便的勾号功能。这里真正的要点是它有try_recv(),它是非阻塞的
我不确定把消息检查器放在这样一个操作循环的中间是多么有用。我还没有发现Actix(或以前的Akka)能够在没有(如上所述)让线程自己完成任务的情况下真正停止线程。所以这就是我现在正在使用的(这里有很大的修正余地,我还在学习自己)
//Cargo.toml:
//[依赖关系]
//横梁通道=“0.4.4”
使用横梁_通道:{发送方,接收方,无界,勾选};
使用std::time::{Duration,Instant};
fn main(){
let(tx,rx):(发送方,接收方)=无界();
设rx2=rx.clone();
//横梁允许克隆和移动接收器
std::thread::spawn(移动| |){
//作品:
//让mut timer=timer::new().unwrap();
//设periodic=timer.periodic(持续时间:毫秒(200));
让ticker:Receiver=tick(std::time::Duration::from_millis(500));
环路{
//作品:
//periodic.recv();
横梁_通道::选择{
recv(股票代码)->{
//OP:在这里做我的工作
println!(“你好,工作。”);
//通信检查:继续工作?
//try_recv是非阻塞的
//rx,单个耗电元件可在横梁中克隆
让try_result=rx2。try_recv();
匹配try_结果{
Err(_e)=>{},
Ok(msg)=>{
匹配msg.as_str(){
“结束世界”=>{
println!(“世界末日”);
打破
},
_ => {},
}
},
_ => {}
}
}
}
}
});
//让工作继续10秒钟,然后告诉线程结束。
std::thread::sleep(std::time::Duration::from_secs(10));
println!(“再见,世界”);
发送(“结束世界”。发送到字符串());
}
对我来说,使用字符串作为消息设备有点畏缩。可以在枚举中执行其他挂起和重新启动操作。为了与其他人共享,@RajeevRanjan建议的解决方案解决了我正在维护的火箭项目中的一个大问题。Rocket框架不包含关闭功能,因此我启动了一个新线程来处理服务器,并使用Condvar
等待它。我尝试使用mpsc
,但使用Condvar
更简单。代码可用。@silvioprog我没有提供此建议;我只是编辑了它。RajeevRanjan是解决方案的作者。当你的线程正在运行阻塞操作时,你看不出该如何工作。@hasufell它不会,但是答案无论如何也不会这样说。如果没有线程方面的合作,就不可能以安全、便携的方式停止线程。渠道是这种合作的一种方式。