How to terminate or pause a Rust thread from another thread?

I spawned a thread with an infinite loop and a timer inside.

thread::spawn(|| { let mut timer = Timer::new().unwrap(); let periodic = timer.periodic(Duration::milliseconds(200)); loop { periodic.recv(); // Do my work here } }); 

Note that although this example was created before Rust 1.0, and the specific types have been modified or removed since then, the general question and concept remain valid.

After a certain time, based on some conditions, I need to stop this flow from another part of my program. In other words, I just want to get out of an infinite loop. How can I do it right? Also, how could I pause this thread and resume it later?

I tried using a global unsafe flag to break the loop, but I think this solution does not look very good.

+7
rust
source share
1 answer

Edit: Updated for Rust 1.x

For both of these tasks (ending and pausing a thread) you can use channels.

This is how a thread can be terminated externally:

 use std::thread; use std::time::Duration; use std::sync::mpsc::{self, TryRecvError}; use std::io::{self, BufRead}; fn main() { println!("Press enter to terminate the child thread"); let (tx, rx) = mpsc::channel(); thread::spawn(move || { loop { println!("Working..."); thread::sleep(Duration::from_millis(500)); match rx.try_recv() { Ok(_) | Err(TryRecvError::Disconnected) => { println!("Terminating."); break; } Err(TryRecvError::Empty) => {} } } }); let mut line = String::new(); let stdin = io::stdin(); let _ = stdin.lock().read_line(&mut line); let _ = tx.send(()); } 

That is, at each iteration of the work cycle, we check whether someone notified us via the channel. If so, or if the other end of the channel is out of scope, we just break the loop.

Here's how a thread can be โ€œpausedโ€ and โ€œresumedโ€:

 use std::time::Duration; use std::thread; use std::sync::mpsc; use std::io::{self, BufRead}; fn main() { println!("Press enter to wake up the child thread"); let (tx, rx) = mpsc::channel(); thread::spawn(move || { loop { println!("Suspending..."); match rx.recv() { Ok(_) => { println!("Working..."); thread::sleep(Duration::from_millis(500)); } Err(_) => { println!("Terminating."); break; } } } }); let mut line = String::new(); let stdin = io::stdin(); for _ in 0..4 { let _ = stdin.lock().read_line(&mut line); let _ = tx.send(()); } } 

Here we use the recv() method, which pauses the stream until something appears on the channel, so to resume the stream, you just need to send something (unit value () in this case) through the channel. If the transmitting end of the channel is omitted, recv() will return Err(()) - we use it to exit the loop.

Channels are the easiest and most natural way (IMO) to complete these tasks, but not the most effective. There are other concurrency primitives that you can find in the std::sync module. They are at a lower level than channels, but can be more effective in specific tasks.

+12
source share

All Articles