簡體   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