2017-04-18 2 views
2

J'ai le code suivant:Comment faire pour abandonner l'environnement d'une fermeture passée à futures-cpupool?

extern crate futures; 
extern crate futures_cpupool; 
extern crate tokio_timer; 

use std::time::Duration; 

use futures::Future; 
use futures_cpupool::CpuPool; 
use tokio_timer::Timer; 

fn work(foo: Foo) { 
    std::thread::sleep(std::time::Duration::from_secs(10)); 
} 

#[derive(Debug)] 
struct Foo { } 

impl Drop for Foo { 
    fn drop(&mut self) { 
     println!("Dropping Foo"); 
    } 
} 

fn main() { 
    let pool = CpuPool::new_num_cpus(); 

    let foo = Foo { }; 

    let work_future = pool.spawn_fn(|| { 
     let work = work(foo); 

     let res: Result<(),()> = Ok(work); 
     res 
    }); 

    println!("Created the future"); 

    let timer = Timer::default(); 
    let timeout = timer.sleep(Duration::from_millis(750)) 
     .then(|_| Err(())); 

    let select = timeout.select(work_future).map(|(win, _)| win); 

    match select.wait() { 
     Ok(()) => { }, 
     Err(_) => { }, 
    } 
} 

Il semble que ce code ne peut pas exécuter Foo::drop - aucun message est imprimé.

Je m'attendais foo à être abandonné dès que timeout avenir se résout en select, car c'est une partie de l'environnement d'une fermeture, passé à l'avenir abandonné.

Comment le faire exécuter Foo::drop?

+1

Il me semble que le 'foo' est utilisé dans un thread qui reste après la fin du programme. Cf. https://users.rust-lang.org/t/stopping-a-thread/6328. Je me demande si http://stackoverflow.com/questions/26199926/how-to-terminate-or-suspend-a-rust-thread-from-another-thread est suffisant pour répondre à votre question? – ArtemGr

Répondre

3

Les documentation for CpuPool states:

Les threads de travail associé à un pool de fil sont maintenus en vie aussi longtemps que il y a une poignée ouverte au CpuPoolou il y a des travaux en cours d'exécution sur les. Une fois que tous les travaux ont été vidés et que toutes les références ont disparu, les threads de travail seront fermés.

De plus, vous transférez la propriété de foo de main à la fermeture, qu'il transfère ensuite à work. work va laisser tomber foo à la fin du bloc. Cependant, work effectue également un bloquant opération de sommeil. Ce sommeil compte comme un travail sur le fil.

Le sommeil continue quand le thread principal se termine, ce qui arrête immédiatement le programme, et tous les threads, sans aucun temps à nettoyer.

Comme indiqué dans How to terminate or suspend a Rust thread from another thread? (et d'autres questions dans d'autres langues), il n'existe aucun moyen sûr de terminer un thread.

Je me attendais foo à être abandonné dès que l'avenir délai d'attente se résorbe en select, car il est une partie de l'environnement d'une fermeture, est passé à l'avenir baissé.

Le futur ne fait pas "avoir" la fermeture ou foo. Tout ce qu'il a est une poignée sur le fil:

pub struct CpuFuture<T, E> { 
    inner: Receiver<thread::Result<Result<T, E>>>, 
    keep_running_flag: Arc<AtomicBool>, 
} 

Étrangement, the docs say:

Si l'avenir est retourné a chuté alors ce sera CpuPooltentative d'annuler le calcul, si possible. Autrement dit, si le calcul est en cours de fonctionnement, il sera interrompu si possible.

Cependant, je ne vois pas la mise en œuvre de Drop pour CpuFuture, donc je ne vois pas comment il pourrait être possible (ou de sécurité). Au lieu de Drop, le pool de threads lui-même exécute un Future. Lorsque ce futur est interrogé, il vérifie si le récepteur a été abandonné. Ce comportement est fourni par le oneshot::Receiver.Cependant, cela n'a rien à voir avec les discussions, qui sont en dehors de la vision du futur.

+3

- "* Cependant, je ne vois aucune implémentation pour Drop pour CpuFuture *" - Le 'Drop' est dans le' Receiver' (voir https://github.com/alexcrichton/futures-rs/blob/master /src/sync/oneshot.rs). – ArtemGr

+0

Donc, il n'y a vraiment aucun moyen d'appeler des destructeurs automatiquement avec des contrats à terme? –

+0

@MichaelPankov Je pense que c'est le mauvais angle pour le regarder. Dans Rust, les destructeurs ne sont pas garantis, mais quand ils le sont, c'est toujours automatique. Les contrats à terme ne sont pas différents - le destructeur sera appelé lorsque la variable sort naturellement de la portée. Votre problème est lié au fait que vous avez démarré un thread qui exécute toujours des tâches lorsque le thread principal se termine. Le problème est complètement orthogonal aux futurs. – Shepmaster