2016-03-09 4 views
8

Quando I spawn un thread in Rust, ottengo un JoinHandle, che è buono per ... unirsi (un'operazione di blocco) e non molto altro. Come posso verificare se un thread secondario è terminato (ovvero, JoinHandle.join() non verrà bloccato) dal thread principale? Punti bonus se sai come uccidere un thread figlio.Come verificare se un thread è finito in Rust?

Immagino di poterlo fare creando un canale, inviando qualcosa al bambino e rilevando errori, ma sembra una complessità e un sovraccarico inutili.

risposta

8

A partire da Rust 1.7, non esiste alcuna API nella libreria standard per verificare se un thread figlio è terminato senza bloccare.

Una soluzione portatile sarebbe quella di utilizzare channels per inviare un messaggio dal figlio al genitore per segnalare che il bambino sta per uscire. Receiver ha un metodo non bloccante try_recv. Quando try_recv riceve un messaggio, è possibile utilizzare join() su JoinHandle per recuperare il risultato del thread.

Esistono inoltre tratti di estensione specifici della piattaforma instabili che consentono di ottenere l'handle di thread raw. Dovresti quindi scrivere codice specifico per piattaforma per verificare se il thread è uscito o meno.

Se pensi che questa funzione debba essere nella libreria standard di Rust, puoi submit an RFC (assicurati di leggere prima il README!).

Punti bonus se si sa come uccidere un thread figlio.

I thread in Rust sono implementati utilizzando thread OS nativi. Anche se il sistema operativo potrebbe fornire un modo per eliminare un thread, è una cattiva idea, perché le risorse che il thread allocato non verranno eliminate fino alla fine del processo .

8

La risposta breve non è ancora possibile. Ma questo non è il punto che dovrebbe essere veramente affrontato.

Punti bonus se si sa come uccidere un thread figlio.

MAI

Anche in lingue che supportano le discussioni abbattimento (see Java here), si raccomanda di non farlo.

d'esecuzione di un filo è generalmente codificato con espliciti punti di interazione, e ci sono spesso assunti impliciti che si verificherà nessun altra interruzione.

L'esempio più eclatante sono ovviamente le risorse: l'ingenuo metodo "kill" sarebbe interrompere l'esecuzione del thread; questo significherebbe non rilasciare alcuna risorsa. Potresti pensare alla memoria, è l'ultima delle tue preoccupazioni. Immaginate, invece, tutti gli Mutex che non sono sbloccati e creeranno deadlock più tardi ...

L'altra opzione sarebbe quella di iniettare un panic nella discussione, che causerebbe lo srotolamento. Tuttavia, non è possibile solo avviare lo svolgimento in qualsiasi momento!Il programma dovrebbe definire i punti di sicurezza in base ai quali iniettare uno panic sarebbe sicuro che sia sicuro (iniettarlo in qualsiasi altro punto significa potenzialmente danneggiare oggetti condivisi); come definire tali punti di sicurezza e iniettare il c'è un problema di ricerca aperto nelle lingue native, specialmente quelle eseguite sui sistemi W^X (dove le pagine di memoria sono sia scrivibili che eseguibili ma mai entrambe).

In sintesi, non esiste un modo noto per eliminare in modo sicuro (sia dal punto di vista della memoria che della funzionalità) un thread.

2

È possibile, amici. Utilizzare i contatori che Rust lascerà cadere su fine o panico. Sicuro al 100%. Esempio:

use std::time::Duration; 
use std::sync::Arc; 
use std::sync::atomic::{AtomicBool, Ordering}; 
use std::thread; 

fn main() { 
    // Play with this flag 
    let fatal_flag = true; 
    let do_stop = true; 

    let working = Arc::new(AtomicBool::new(true)); 
    let control = Arc::downgrade(&working); 

    thread::spawn(move || { 
     while (*working).load(Ordering::Relaxed) { 
      if fatal_flag { 
       panic!("Oh, my God!"); 
      } else { 
       thread::sleep(Duration::from_millis(20)); 
       println!("I'm alive!"); 
      } 
     } 
    }); 

    thread::sleep(Duration::from_millis(50)); 

    // To stop thread 
    if do_stop { 
     match control.upgrade() { 
      Some(working) => (*working).store(false, Ordering::Relaxed), 
      None => println!("Sorry, but thread died already."), 
     } 
    } 

    thread::sleep(Duration::from_millis(50)); 

    // To check it's alive/died 
    match control.upgrade() { 
     Some(_) => println!("Thread alive!"), 
     None => println!("Thread ends!"), 
    } 
} 

Gist: https://gist.github.com/DenisKolodin/edea80f2f5becb86f718c330219178e2

al campo da giuoco: https://play.rust-lang.org/?gist=9a0cf161ba0bbffe3824b9db4308e1fb&version=stable&backtrace=0

UPD: Ho creato thread-control cassa che implementa questo approccio: https://github.com/DenisKolodin/thread-control