2015-06-18 41 views
9

这似乎是锈一个常见的成语产卵关闭一个线程阻塞的IO,所以你可以使用非阻塞渠道:如何可靠地清理阻塞IO的锈线程?

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; 
      } 
     } 
    }); 
} 

的问题是,再结合这样的线程取决于产生的线程上“实现通过克隆

drop(accept_rx); 
listener_thread.join(); // blocks until listener thread reaches accept_tx.send(..) 

你可以让虚拟连接的TcpListener秒,关机TcpStream S,但这些看起来像真的哈克:“信道的接收端已被删除(即调用send(..)回报Err(_))清理这种方法的方法读取,并且就目前而言,我甚至不知道的破解在从stdin的读取中触发线程阻塞加入。

我该如何清理这些线程,还是我的架构错了?

+3

无法立即可靠地清理线程的一般模式是通知它们清理,让它们运行并确保它们不再产生副作用。对于不可接受的TcpListener,但对于传出请求或文件操作,通常是这样。 – usr

+1

@usr好的,但我正在寻找Rust解决方案。 (我猜,它不需要完全适合那个模具。)我问这个问题,因为我一直无法找到使用当前(安全)API的方式。 – sleeparrow

+1

http://www.rust-lang.org/ – sleeparrow

回答

-1

tldr;虚拟连接可能是最简单的方法。

(我假设Linux作为操作系统。)

listener.incoming()将调用。接受()上的TcpListener在它的.next()方法 和线程将被卡在接受调用操作系统。据我所知,只有通过连接尝试或信号,或者如果套接字被设置为非阻塞,才可以自愿回复。

信号处理似乎不被锈标准库支持。

套接字的文件描述符似乎无法在TcpListener中访问,因此您无法将其设置为非阻塞模式。此外, 意味着投票,这可能是一个坏主意。

另一种可能是使用mio,因为它提供了一个事件循环。您可以针对事件循环定制整个应用程序,并且不需要执行线程,也可以为每个线程使用事件循环,这可能会阻止 并让它听取额外的管道,以便您可以唤醒它它可以将其关闭。第一个可能不再可行,这取决于你已经有多少代码,第二个代码听起来像是过度杀毒。

+0

-1。在我的问题中,大部分都被提及是不可取的。 'mio'箱子是一个有效的建议,但它现在还不支持Windows。我也很确定你不能只为线程添加一个“管道”(通道?)来侦听中断;他们阻止了对'read'的调用。如果您认为有一种方法可以按照您的描述进行操作,请举例说明。 – sleeparrow

+0

我不知道,窗户上的情况如何。但是在Linux和许多其他* nixes中,有epoll,kqueue和select等机制,在这些机制中,您可以注册文件描述符并获得唤醒和通知,如果有任何文件描述符存在的话。管道只是一对文件描述符,在那里你可以写入一个文件并在另一个文件上读取。读取端将被转移到线程进行清理,写入端将保留在控制线程中,因此可以唤醒过度唤醒。如果它对您有任何用处,我可以使用nix crate作为例子。但是这对w不起作用。 –

+0

这个问题不是“我怎么能在Rust中多路复用流?”,而是“我如何可靠地,一般地清理在Rust中阻塞IO的线程?”。 – sleeparrow

1

在Windows或Linux/Unix/POSIX中,一个不能安全地取消线程是可靠的,所以它在Rust标准库中不可用。

Here is an internals discussion about it

有很多来自强制取消线程的未知数。它会变得非常混乱。除此之外,线程和阻塞I/O的组合总是会面临这个问题:您需要每个阻塞I/O调用都有超时,因此它甚至有可能可靠地中断。如果不能编写异步代码,则需要使用进程(具有定义的边界并可由操作系统强制结束,但明显面临更重的权重和数据共享挑战)或非阻塞I/O将您的线程置回可中断的事件循环中。

mio可用于异步代码。 Tokio是基于mio的更高级别的包,它使得编写非阻塞异步代码更加直截了当。