2014-10-05 20 views
7

Ho generato una discussione con un ciclo infinito e un timer all'interno.Come terminare o sospendere un thread di Rust da un altro thread?

thread::spawn(|| { 
    let mut timer = Timer::new().unwrap(); 
    let periodic = timer.periodic(Duration::milliseconds(200)); 
    loop { 
     periodic.recv(); 

     // Do my work here 
    } 
}); 

nota che mentre questo esempio è stato creato prima ruggine 1,0 ei tipi specifici hanno cambiato o è stato rimosso da allora, la questione generale e il concetto rimane valido

Dopo un tempo in base ad alcune condizioni, Devo terminare questa discussione da un'altra parte del mio programma. In altre parole, voglio solo uscire dal ciclo infinito. Come posso farlo correttamente? Inoltre, come posso sospendere questo thread e riprenderlo in seguito?

Ho provato a utilizzare un flag globale non sicuro per interrompere il ciclo, ma penso che questa soluzione non sia piacevole.

risposta

12

Edit: aggiornato per Rust 1.x

Per entrambi questi compiti (terminare e sospendere un filo) è possibile utilizzare i canali.

Ecco come un filo potrebbe essere chiuso esternamente:

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

Cioè, ad ogni iterazione di un ciclo lavoratore che controllare se qualcuno ci ha comunicato attraverso un canale. Se sì o se l'altra estremità del canale è uscita dal campo di applicazione, interrompiamo il ciclo.

Ecco come un filo potrebbe essere "sospeso" e "riprese":

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

Qui usiamo recv() metodo che sospende il filo fino a quando qualcosa arriva sul canale, così al fine di riprendere il filo si solo bisogno di inviare qualcosa (valore unitario () in questo caso) attraverso il canale. Se la parte trasmittente del canale viene interrotta, recv() restituirà Err(()) - lo usiamo per uscire dal ciclo.

I canali sono il modo più semplice e più naturale (IMO) per eseguire queste attività, ma non la più efficiente. Esistono altre primitive di concorrenza che puoi trovare nel modulo std::sync. Appartengono a un livello inferiore rispetto ai canali, ma possono essere più efficienti in determinati compiti.

Problemi correlati