IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Rust Discussion :

Durée de vie statique et thread


Sujet :

Rust

  1. #1
    Membre émérite
    Avatar de Nothus
    Homme Profil pro
    aucun
    Inscrit en
    Juillet 2009
    Messages
    200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : aucun
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2009
    Messages : 200
    Points : 2 575
    Points
    2 575
    Billets dans le blog
    27
    Par défaut Durée de vie statique et thread
    Bonjour à tous,

    Un problème retors de durée de vie se pose à moi, que j'ai grandement simplifié ici...

    Je partage un AtomicU8 entre plusieurs treads. Ces derniers n'ont aucune durée de vie qui dépasse la fonction qui les appelle.

    Pourtant le compilateur se plaint "`a` does not live long enough" et demande que l'"argument requires that `a` is borrowed for `'static`".

    Code rust : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    use std::thread::{self, JoinHandle}; 
    use std::sync::atomic::{AtomicU8, Ordering};
     
    fn lanceur() { 
     
        let a = AtomicU8::new( 0 ); 
     
        let mut vecteur: Vec<JoinHandle<()>> = Vec::new(); 
     
        for i in 1..10 { 
            let y = i; 
            let ref_a = &a; 
            vecteur.push( thread::spawn( 
                move || { 
                    println!("n = {}", y); 
                    ref_a.fetch_add(y, Ordering::SeqCst); 
                } 
            ) ); 
        } 
     
        for v in vecteur { 
            v.join(); 
        } 
     
        println!( "{}", a.load( Ordering::Relaxed ) ); 
    } 
     
    fn main() { 
     
        lanceur(); // je suis sûr que mes threads lancés dans cette fonction, n'auront pas une durée plus longue qu'elle 
     
    }

    Jusque là d'accord : j'imagine qu'il ne cherche pas à savoir s'il peut connaître la durée de vie d'un thread, et donc demande forcément une référence statique.

    Grand seigneur que je suis, je m'exécute :

    Code rust : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    fn lanceur() { 
     
        static a: std::sync::atomic::AtomicU8 = AtomicU8::new( 0 ); 
     
    	...

    Pas de problème : ça compile, et ça me donne bien 45. Parfait. Ou presque. Car comme j'ai mis 'a' en statique, évidemment un second appel me retourne 90 :

    Code rust : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    fn main() { 
     
        lanceur(); // a = 45 
        lanceur(); // a = 45+45 = 90 
     
    }

    Du coup si j'ai l'outrecuidance d'avoir ma fonction "lanceur" elle-même dans un thread, je pars évidemment dans le décor (certes le résultat final sera toujours le même).

    Code rust : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    fn main() { 
     
        let mut vecteur: Vec<JoinHandle<()>> = Vec::new(); 
        for y in 0..5 { 
            vecteur.push( thread::spawn( || { lanceur(); } ) ); 
        } 
        for v in vecteur { 
            v.join(); 
        } 
     
    }

    Là je sèche. Comment négocier une durée de vie dans un tel cas, finalement assez commun ? J'ai regardé les docs sur les durées de vie sans trouver une piste.

    Précision : ici j'ai partagé directement mon AtomicU8. Dans la réalité de mon code, je passe par une structure pour le partage avec quelques autres champs. La structure est d'ailleurs créée pour être possédée par le thread.

    Votre aide me serait précieuse...

    Bonne journée à tous,

    Julien.
    "En dehors des langages de la famille LISP et du modèle RDF, point de salut."

  2. #2
    Membre émérite
    Avatar de Nothus
    Homme Profil pro
    aucun
    Inscrit en
    Juillet 2009
    Messages
    200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : aucun
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2009
    Messages : 200
    Points : 2 575
    Points
    2 575
    Billets dans le blog
    27
    Par défaut
    Décidément j'ai tendance à répondre par moi-même car je fais les choses trop vite !

    Problème résolu avec Arc, qui comptera les références et libère au bon moment. Pas besoin de Mutex comme l'opération est atomique... C'était tout bête !

    Code rust : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
     
    use std::thread::{self, JoinHandle}; 
    use std::sync::atomic::{AtomicU8, Ordering};
    use std::sync::Arc; 
     
    fn lanceur() { 
     
        //let a = AtomicU8::new( 0 ); 
        let a: Arc<AtomicU8> = Arc::new( AtomicU8::new( 0 ) ); 
     
        let mut vecteur: Vec<JoinHandle<()>> = Vec::new(); 
     
        for i in 1..10 { 
            let ref_a = a.clone(); 
            vecteur.push( thread::spawn( 
                move || { 
                    println!("n = {}", i); 
                    ref_a.fetch_add(i, Ordering::SeqCst); 
                } 
            ) ); 
        } 
     
        for v in vecteur { 
            v.join(); 
        } 
     
        println!( "{}", a.load( Ordering::Relaxed ) ); 
    } 
     
    fn main() { 
     
        let mut vecteur: Vec<JoinHandle<()>> = Vec::new(); 
        for _ in 0..5 { 
            vecteur.push( thread::spawn( || { lanceur(); } ) ); 
        } 
        for v in vecteur { 
            v.join(); 
        } 
     
    }
    "En dehors des langages de la famille LISP et du modèle RDF, point de salut."

  3. #3
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Bonjour,

    En fait, le problème du couple std::thread::spawn / std::thread::JoinHandle::join est qu'il n'est généralement pas adapté au borrow checker de Rust. En effet, le borrow checker ne tient pas compte des appels à std::thread::JoinHandle::join pour voir où s'arrêtent les threads. Du coup, std::thread::spawn impose que la callback et son type de retour aient une durée de vie statique, d'où les utilisations lourdes et redondantes de std::sync::Arc.

    Néanmoins, il est possible d'échapper aux limites du couple std::thread::spawn / std::thread::JoinHandle::join en utilisant le crate rayon, par exemple via la fonction rayon::scope (voir la documentation).

    D'ailleurs, le fait de remplacer le couple std::thread::spawn / std::thread::JoinHandle::join par une fonction comme rayon::scope s'inscrit dans un paradigme qui s'appelle la programmation concurrente structurée, que presque personne ne connaît.

    Ce paradigme est très bien expliqué dans un excellent article de Nathaniel J. Smith dont je conseille vivement la lecture : Notes on structured concurrency, or: Go statement considered harmful

  4. #4
    Membre émérite
    Avatar de Nothus
    Homme Profil pro
    aucun
    Inscrit en
    Juillet 2009
    Messages
    200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : aucun
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2009
    Messages : 200
    Points : 2 575
    Points
    2 575
    Billets dans le blog
    27
    Par défaut
    Merci beaucoup pour toutes les explications ! Je vais approfondir cette approche de la programmation concurrentielle structurée de suite...
    "En dehors des langages de la famille LISP et du modèle RDF, point de salut."

  5. #5
    Membre émérite
    Avatar de Nothus
    Homme Profil pro
    aucun
    Inscrit en
    Juillet 2009
    Messages
    200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : aucun
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2009
    Messages : 200
    Points : 2 575
    Points
    2 575
    Billets dans le blog
    27
    Par défaut
    Grosse claque à la lecture de l'article, il me faudra un peu de temps pour digérer tout ça. L'idée de la nurserie est effectivement brillante.

    Pour le sujet de la programmation concurrente structurée, effectivement, Google ne retourne aucun résultat français. Crotte : ça sent quelques heures à la bibliothèque universitaire ça !
    "En dehors des langages de la famille LISP et du modèle RDF, point de salut."

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. ThreadManager et durée de vie d'un thread
    Par Trunks dans le forum Windows
    Réponses: 7
    Dernier message: 07/01/2010, 16h51
  2. [C#] : Durée de vie d'un thread
    Par dcollart dans le forum C#
    Réponses: 2
    Dernier message: 04/12/2006, 18h08
  3. [savoir] durée de vie d'un PC?
    Par afrikha dans le forum Composants
    Réponses: 20
    Dernier message: 24/10/2005, 13h28
  4. [AS2] durée de vie d'une classe (extends movieclip)
    Par ooyeah dans le forum ActionScript 1 & ActionScript 2
    Réponses: 4
    Dernier message: 23/07/2005, 13h33
  5. prob de durée de vie de IDvdGraphBuilder
    Par Chaksss dans le forum DirectX
    Réponses: 11
    Dernier message: 30/12/2004, 16h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo