Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

This is my code:

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

How do I create a situation where the thread will be terminated or killed if the connection didn't finish in N seconds?

The reason for all of this is that Rust has no way to set a socket connection timeout so I have no way to ensure the program won't get stuck.

like image 724
Ba7a7chy Avatar asked Mar 23 '16 15:03

Ba7a7chy


People also ask

How do you set a timeout in Rust?

pub fn new(value: T, timeout: Duration) -> Timeout<T> [src][−] Create a new Timeout that allows value to execute for a duration of at most timeout .

How do you block a thread in Rust?

park and unparkThe thread::park function blocks the current thread unless or until the token is available for its thread handle, at which point it atomically consumes the token. It may also return spuriously, without consuming the token.

What is thread in Rust?

Rust provides a mechanism for spawning native OS threads via the spawn function, the argument of this function is a moving closure. use std::thread; const NTHREADS: u32 = 10; // This is the `main` thread.

How many threads can Rust run?

The threads provided by the Rust standard library are "OS threads", that is, they use the facilities of your operating system. Therefore, a Rust program has no limit imposed by Rust itself, but rather, this limit would result from whatever your OS lets you do.


1 Answers

As @Shepmaster noted: it's a bad idea to terminate threads.

What you can do instead is to give the thread a Sender through which it should notify you if it has successfully opened a connection (maybe even by sending you the handle). Then you can let your main thread sleep for the time you wish to wait. When your thread wakes up, it checks its corresponding Receiver for some sign of life from the thread. In case the thread did not answer, just release it into the wild by dropping the JoinHandle and the Receiver. It's not like it's consuming cpu-time (it's blocked), and it's not consuming too much memory. If it ever unblocks, it'll detect that the Sender is not connected and can shut down for good.

Of course you should not have bazillions of these open threads, because they still use resources (memory and system thread handles), but on a normal system that's not too much of an issue.

Example:

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!(),
    }
}
like image 110
oli_obk Avatar answered Oct 17 '22 05:10

oli_obk