Rust如何终止一个线程

您所在的位置:网站首页 rust怎么取消自动奔跑 Rust如何终止一个线程

Rust如何终止一个线程

2024-05-30 14:43| 来源: 网络整理| 查看: 265

实际测试中还是碰到了其他的问题。我执行的这个外部命令是通过make调用gradle进行编译打包的,经过观察使用child.kill()确实会把make进程给干掉,但是gradle进程并没有被干掉,在gradle没被干掉的时候rust启动的线程还是在运行不会终止。各位大佬有解决这个问题的办法吗?(注:gradle概率假死,导致资源不会被释放) 下面是代码:

pub async fn execute_command( cmd: &str, work_dir: &str, args: Option, log_name: String, ) -> AppResult { info!("execute: {} {:?}", cmd, args); let mut command = Command::new(cmd); command .current_dir(work_dir) .stdout(Stdio::piped()) .stderr(Stdio::piped()); let key = format!("{} {:?}", cmd, args); if let Some(args) = args { command.args(args); } let mut child = command.spawn()?; let (send, recv) = channel::(); { get_signal_senders().insert(key.clone(), send); } let stdout = match child.stdout.take() { Some(s) => s, None => return Ok(()), }; // 虽然后面的child.kill()执行了,但是这里因为gradle进程还在执行并不会终止 std::thread::spawn(move || { tracing::subscriber::with_default(create_log_subscriber(&log_name), || { let mut reader = BufReader::new(stdout).lines(); while let Some(line) = match get_runtime().block_on(reader.next_line()) { Ok(line) => line, Err(e) => { warn!("读取错误: {}", e); return; } } { info!("{}", line); } info!("===> 命令执行结束,输出线程退出!!!"); }); }); tokio::select! { rstatus = child.wait() => { get_signal_senders().remove(&key); match rstatus { Ok(status) => { if !status.success() { match child.stderr.take() { Some(stderr) => { let mut reader = BufReader::new(stderr).lines(); while let Ok(Some(line)) = reader.next_line().await { error!("{}", line); } } None => warn!("未获取到标准错误输出,忽略..."), } return Err(anyhow::anyhow!("命令执行失败: {}", status.to_string())); } } Err(e) => { error!("执行命令错误: {}", e); return Err(anyhow::anyhow!("命令执行失败: {}", e)); } } } _ = recv => { child.kill().await.expect("kill failed"); return Err(anyhow::anyhow!("命令被强行终止,执行失败!")); } }; Ok(()) }

-- 👇 griffenliu: 在tokio的API中找到了这个,应该可以解决我的问题了。

/// Forces the child to exit. /// /// This is equivalent to sending a SIGKILL on unix platforms. /// /// If the child has to be killed remotely, it is possible to do it using /// a combination of the select! macro and a oneshot channel. In the following /// example, the child will run until completion unless a message is sent on /// the oneshot channel. If that happens, the child is killed immediately /// using the `.kill()` method. /// /// ```no_run /// use tokio::process::Command; /// use tokio::sync::oneshot::channel; /// /// #[tokio::main] /// async fn main() { /// let (send, recv) = channel::(); /// let mut child = Command::new("sleep").arg("1").spawn().unwrap(); /// tokio::spawn(async move { send.send(()) }); /// tokio::select! { /// _ = child.wait() => {} /// _ = recv => child.kill().await.expect("kill failed"), /// } /// } /// ```

-- 👇 griffenliu: 嗯,确实,控制线程很难,综合前面几位大佬的回复,我基本确定了应该在适合的时候终止Command而不是想着怎么去杀死线程。我使用的是tokio::process:Command。下面是代码,大佬帮忙看看如何修改来在卡死的时候自动终止?万分感谢:

pub async fn execute_command(cmd: &str, work_dir: &str, args: Option) -> AppResult { info!("execute: {} {:?}", cmd, args); let mut command = Command::new(cmd); command .current_dir(work_dir) .stdout(Stdio::piped()) .stderr(Stdio::piped()); if let Some(args) = args { for arg in args { command.arg(arg); } } let mut child = command.spawn()?; let stdout = match child.stdout.take() { Some(s) => s, None => return Ok(()), }; let mut reader = BufReader::new(stdout).lines(); while let Some(line) = reader.next_line().await? { info!("{}", line); } let status = child.wait().await?; if !status.success() { match child.stderr.take() { Some(stderr) => { let mut reader = BufReader::new(stderr).lines(); while let Some(line) = reader.next_line().await? { error!("{}", line); } } None => warn!("未获取到标准错误输出,忽略..."), }; return Err(anyhow!("Execute Command Error!")); } Ok(()) }

-- 👇 Pikachu: 我不理解。

你调用外部程序用的是std::process::Command吗?如果是的话,这个spawn出来的Child是支持try_wait的。

从线程外部取消线程在哪个语言里面都是个难题,因为很难做资源释放之类的。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3