How do I perform interruptible sleep in Rust?
Asked Answered
S

2

6

I am writing a Rust program that does an action every 2 seconds. The program also uses the ctrlc crate to handle interrupts. However, in some cases, I have to wait up to 2 secs when killing the process. I am using the default std::thread::sleep function, which I seemingly cannot interrupt.

Here comes my question. Is it possible for me to make my program sleep in an interruptible way? In other words, does Rust have a default feature for interrupting a sleeping program? I know that C automatically interrupts any sleep function when the SIGINT signal is received.

Schramm answered 25/11, 2021 at 17:24 Comment(1)
Can you share a snippet to replicate your problem? Does the signal handler exit the process when catching SIGINT? I'm not able to reproduce the issue when a) sleeping on the main thread or b) sleeping on a spawned thread and join()ing it on the main thread. The only time the program waits for the sleeps to expire is when the ctrlc handler does not call std::process::exitBussey
B
2

Your signal handler needs to either make the running threads somehow stop or exit the process upon catching the signal.

Exitting the process is simple: call std::process::exit() in the signal handler after your cleanup is done.

Forwarding the signal to your sleeping threads is harder, you might be able to do that by setting some flag in an Arc<AtomicBool> upon catching SIGINT and repeatedly check that flag with shorter intermittent sleeps in between checks instead of a single longer sleep.

You could also come up with a solution based on channels where your ctrlc handler communicates with the running threads through a broadcast channel and waits for them to respond with some kind of done message before exitting the process. This done message could be through the sending end of a channel that the shutdown handler passes to the running thread. It could then wait with a timeout before force-quitting with std::process::exit.

Bussey answered 25/11, 2021 at 20:22 Comment(3)
I implemented the solutions I proposed with the ctrlc crate, although I only tested on linux. Does the handler not get executed on windows?Bussey
I just completely forgot that I could do the cleanup in the signal handler. Sorry for wasting you time. Thanks !Schramm
It is executed, I just didn't executed std::process::exitSchramm
A
10

If you only want to cleanup and exit, then you can just call std::process::exit in the signal handler as suggested by the other answer. However if you want your threads to stop so that your application can proceed to some other task, you can use a channel and recv_timeout to get an interruptible sleep:

use std::thread;
use std::time::Duration;
use std::sync::mpsc;

let (send, recv) = mpsc::channel();

thread::spawn(move || {
    // When you want to sleep
    if let Ok(_) = recv.recv_timeout (Duration::from_secs (2)) {
        // Sleep was interrupted
        return;
    }
    // Slept for 2s, proceeding
});

// And elsewhere when you want to interrupt the thread:
send.send(());
Apulia answered 26/11, 2021 at 8:38 Comment(0)
B
2

Your signal handler needs to either make the running threads somehow stop or exit the process upon catching the signal.

Exitting the process is simple: call std::process::exit() in the signal handler after your cleanup is done.

Forwarding the signal to your sleeping threads is harder, you might be able to do that by setting some flag in an Arc<AtomicBool> upon catching SIGINT and repeatedly check that flag with shorter intermittent sleeps in between checks instead of a single longer sleep.

You could also come up with a solution based on channels where your ctrlc handler communicates with the running threads through a broadcast channel and waits for them to respond with some kind of done message before exitting the process. This done message could be through the sending end of a channel that the shutdown handler passes to the running thread. It could then wait with a timeout before force-quitting with std::process::exit.

Bussey answered 25/11, 2021 at 20:22 Comment(3)
I implemented the solutions I proposed with the ctrlc crate, although I only tested on linux. Does the handler not get executed on windows?Bussey
I just completely forgot that I could do the cleanup in the signal handler. Sorry for wasting you time. Thanks !Schramm
It is executed, I just didn't executed std::process::exitSchramm

© 2022 - 2024 — McMap. All rights reserved.