2016-05-22 8 views
1

Ich versuche, eine Parameterstruktur zu erstellen, die möglicherweise zwischen Threads geteilt werden. Es hat ein Mitglied namens layer_storage, das einige Mitglieder mutieren müssen. Ich habe den folgenden Code ausprobiert, bekomme aber einen Fehler, der besagt, dass der geklonte Arc nicht lange genug lebt. Das gleiche Mitglied arbeitete gut vor der Hinzufügung von Arc<Mutex<>>.Arc Lebensdauer dauert nicht lange genug von clone()

use std::sync::{Arc, Mutex}; 

#[derive(Clone)] 
pub struct Params { 
    pub optional: Vec<f32>, 
} 

pub struct ParamManager { 
    layer_storage: Arc<Mutex<Vec<Params>>>, 
} 

impl Default for ParamManager { 
    fn default() -> ParamManager { 
     ParamManager { 
      layer_storage: Arc::new(Mutex::new(vec![Params { optional: vec![1.0f32, 2.0f32] }, 
                Params { optional: vec![3.0f32, 4.0f32] }])), 
     } 
    } 
} 

impl ParamManager { 
    pub fn get_mut_params(&mut self, layer_index: usize) -> &mut Params { 
     let layers_arc = self.layer_storage.clone(); 
     let layers = layers_arc.get_mut().unwrap(); 
     // tried this initially: 
     // let layers = self.layer_storage.clone().get_mut().unwrap(); 
     assert!(layers.len() - 1 >= layer_index); 
     &mut layers[layer_index] 
    } 
} 

fn main() { 
    let mut bla = ParamManager::default(); 
    let i = bla.get_mut_params(0); 
} 

(Playground)

+0

Haben Sie versucht, den Klon zu einer Variablen zuzuweisen, gehen Sie dann den Rest in einer gesonderten Erklärung? – ZeissS

+0

Ja, das habe ich gemacht: self.layer_storage.clone() und arbeite dann damit als Variable. – bge0

Antwort

2

Wie @Shempmaster sagt, können Sie nicht einfach einen Verweis auf etwas innerhalb der Arc<Mutex<T>> von der get_mut_params; Dies ist eine der Garantien, die Sie von ihnen bekommen!

Eine Lösung, die in einigen Fällen funktioniert, ist die Funktion umkehren; anstatt eine veränderbare Referenz Rückkehr, einen Verschluss nehmen, die die veränderbare Referenz gegeben:

impl ParamManager { 
    pub fn with_mut_params<F>(&mut self, layer_index: usize, mut f: F) 
        where F: FnMut(&mut Params) { 
     let layers_arc = self.layer_storage.clone(); 
     let layers = layers_arc.lock().unwrap(); 
     f(&mut layers[layer_index]); 
    } 
} 

fn main() { 
    let mut bla = ParamManager::default(); 

    // Context used by the closure 
    let some_var: i32 = 7; 
    let other_var: mut MyContext = do_something(); 

    bla.with_mut_params(0, |i| { 
     // do stuff with i 
     ... 
     // A closure has access to surrounding variables 
     other_var.foo(i, some_var); 
    }); 

} 
+0

Danke, das ist eine ziemlich elegante Art, das Problem zu lösen. Das einzige Problem, das ich hier sehe, ist die Generalisierbarkeit: d. H. Die Schließung akzeptiert nur einen Parameter. Wenn ein bestimmter Kontext benötigt wird, funktioniert dies möglicherweise nicht so gut (insbesondere da Rost keine Überladung aufweist). – bge0

+0

Da es sich um einen Abschluss und nicht nur um einen Funktionszeiger handelt, kann dieser Kontext enthalten sein. Können Sie ein Beispiel geben, das zeigt, was nicht möglich ist? –

+0

Da Sie 'wo F: FnMut (& mut Params)' haben, ist die einzige Art von akzeptablem Abschluss eine, die nur '& mut Params' akzeptiert, richtig? Angenommen, eine Funktion würde ein paar benötigen, zB: 'wo F: FnMut (& mut Params)' ** und ** wo 'F: FnMut (& mut Params, & MyContext, i32)' würde dies zwei verschiedene überladene Ops für dieses benötigen nicht möglich (ohne eine Reihe von 'Optional <>' s ist ein wenig hässlich – bge0

1

Ich denke, der Compiler direkt in Ihrem Fall ist.

Es gibt zwei offensichtliche Fehler hier:

  1. Der layers_arc Wert lebt nur bis zum Satzende, und dann ist es destructor den Referenzzähler dekrementieren und vielleicht den gesamten Wert fallen. Oder es könnte in anderen Thread jederzeit fallengelassen werden. Daher ist es illegal, einen Zeiger auf den Inhalt zurückzusetzen.

  2. Mutex::get_mut Methode erfordert &mut self, während es unmöglich ist, es direkt von Arc zu bekommen.

Sie müssen also Ihren Code irgendwie umgestalten. Zum Beispiel könnten Sie jedes einzelne Element im Vektor mit Arc<Mutex> überwachen und sie mit dem Wert .clone() zurückgeben.

+0

Danke @swizard. Dies ist auch eine gültige Antwort. Ich entschied mich einfach für die Sauberkeit. – bge0