繁体   English   中英

在 Rust 中为线程或函数创建超时的正确方法是什么?

[英]What is the correct way in Rust to create a timeout for a thread or a function?

这是我的代码:

use std::net;
use std::thread;

fn scan_port(host: &str, port: u16) -> bool {
    let host = host.to_string();
    let port = port;
    let t = thread::spawn(move || net::TcpStream::connect((host.as_str(), port)).is_ok());

    t.join().unwrap()
}

如果连接未在 N 秒内完成,如何创建线程将被终止或终止的情况?

所有这一切的原因是 Rust 无法设置套接字连接超时,所以我无法确保程序不会卡住。

正如@Shepmaster 指出的那样:终止线程是个坏主意。

相反,您可以做的是为线程提供一个Sender ,如果它已成功打开连接,它应该通过它通知您(甚至可能通过向您发送句柄)。 然后你可以让你的主线程在你希望等待的时间内sleep 当您的线程唤醒时,它会检查其相应的Receiver是否有来自线程的一些生命迹象。 如果线程没有回答,只需通过删除JoinHandleReceiver将其释放到野外即可 它不像在消耗 cpu 时间(它被阻塞),也没有消耗太多内存。 如果它解除阻塞,它将检测到Sender未连接并且可以永久关闭。

当然,你不应该有无数的这些开放线程,因为它们仍然使用资源(内存和系统线程句柄),但在正常系统上这不是什么大问题。

示例:

use std::net;
use std::thread;
use std::sync::mpsc;

fn scan_port(host: &str, port: u16) -> bool {
    let host = host.to_string();
    let port = port;
    let (sender, receiver) = mpsc::channel();
    let t = thread::spawn(move || {
        match sender.send(net::TcpStream::connect((host.as_str(), port))) {
            Ok(()) => {}, // everything good
            Err(_) => {}, // we have been released, don't panic
        }
    });

    thread::sleep(std::time::Duration::new(5, 0));

    match receiver.try_recv() {
        Ok(Ok(handle)) => true, // we have a connection
        Ok(Err(_)) => false, // connecting failed
        Err(mpsc::TryRecvError::Empty) => {
            drop(receiver);
            drop(t);
            // connecting took more than 5 seconds
            false
        },
        Err(mpsc::TryRecvError::Disconnected) => unreachable!(),
    }
}

@ker 的回答将始终等待 5 秒,即使连接完成得更快。 这是一种类似的方法,超时和网络请求发生在不同的线程上,第一个完成的获胜:

let (sender, receiver) = mpsc::channel();
let tsender = sender.clone();
let t = thread::spawn(move || {
    match sender.send(Ok(net::TcpStream::connect((host.as_str(), port)))) {
        Ok(()) => {}, // everything good
        Err(_) => {}, // we have been released, don't panic
    }
});
let timer = thread::spawn(move || {
  thread::sleep(Duration::from_millis(5000));
  match tsender.send(Err(MyTimeoutError)) {
    Ok(()) => {}, // oops, we timed out
    Err(_) => {}, // great, the request finished already
  }
});
return receiver.recv().unwrap();

但只要你这样做,你不妨使用recv_timeout代替:

let (sender, receiver) = mpsc::channel();
let t = thread::spawn(move || {
    match sender.send(net::TcpStream::connect((host.as_str(), port))) {
        Ok(()) => {}, // everything good
        Err(_) => {}, // we have been released, don't panic
    }
});
return receiver.recv_timeout(Duration::from_millis(5000));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM