如何可靠地清理执行阻塞 IO 的 Rust 线程?
Posted
技术标签:
【中文标题】如何可靠地清理执行阻塞 IO 的 Rust 线程?【英文标题】:How can I reliably clean up Rust threads performing blocking IO? 【发布时间】:2015-09-03 13:42:06 【问题描述】:生成阻塞 IO 的线程似乎是 Rust 中的一个常见习惯用法,因此您可以使用非阻塞通道:
use std::sync::mpsc::channel;
use std::thread;
use std::net::TcpListener;
fn main()
let (accept_tx, accept_rx) = channel();
let listener_thread = thread::spawn(move ||
let listener = TcpListener::bind(":::0").unwrap();
for client in listener.incoming()
if let Err(_) = accept_tx.send(client.unwrap())
break;
);
问题是,像这样重新加入线程取决于生成的线程“意识到”通道的接收端已被丢弃(即,调用send(..)
返回Err(_)
):
drop(accept_rx);
listener_thread.join(); // blocks until listener thread reaches accept_tx.send(..)
您可以为TcpListener
s 建立虚拟连接,并通过克隆关闭TcpStream
s,但这些似乎是清理此类线程的非常老套的方法,就目前而言,我什至不知道hack 触发线程阻塞,从stdin
读取加入。
我该如何清理这样的线程,还是我的架构有问题?
【问题讨论】:
对于无法立即可靠清理的线程,一般的模式是通知它们清理,让它们运行并确保它们不再产生副作用。对于不可接受的 TcpListener,但对于传出请求或文件操作,它通常是可接受的。 @usr 是的,但我正在寻找 Rust 解决方案。 (我猜它不需要完全适合那个模具。)我问这个问题是因为我无法找到使用当前(安全)API 的方法。 rust-lang.org 【参考方案1】:在 Windows 或 Linux/Unix/POSIX 中根本无法安全地可靠地取消线程,因此它在 Rust 标准库中不可用。
Here is an internals discussion about it.
强行取消线程有很多未知数。它会变得非常混乱。除此之外,线程和阻塞 I/O 的组合将始终面临这个问题:您需要每个阻塞 I/O 调用都有超时,以便它甚至有机会被可靠地中断。如果不能编写异步代码,则需要使用进程(具有定义的边界并且可以由操作系统强制结束,但显然会带来更大的权重和数据共享挑战)或非阻塞 I/O,这将将您的线程重新置于可中断的事件循环中。
mio 可用于异步代码。 Tokio 是基于 mio 的更高级别的 crate,它使编写非阻塞异步代码更加直接。
【讨论】:
以上是关于如何可靠地清理执行阻塞 IO 的 Rust 线程?的主要内容,如果未能解决你的问题,请参考以下文章
Rust futures: async fn 中的 thread::sleep 和阻塞调用