2016-05-22 17 views
1

スレッド間で共有される可能性のあるパラメータ構造体を作成しようとしています。メンバーにはlayer_storageという名前のメンバーがいます。私は次のコードを試しましたが、クローン化されたArcが十分に長くは生きていないというエラーが表示されています。この同じメンバーは、Arc<Mutex<>>の追加の前にうまくいきました。アークの寿命が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

を、あなたは別の文で残りを行い、その後、変数にクローンを割り当てようとしましたか? – ZeissS

+0

はい、それは私がやったことです:self.layer_storage.clone()そしてそれを変数として扱います。 – bge0

答えて

2

@Shepmasterによると、Arc<Mutex<T>>の中の何かへの参照をget_mut_paramsから戻すことはできません。これはあなたがそれらから得る保証の一つです!

場合によっては機能する1つの解決策は、機能を内側に回すことです。むしろ、変更可能な参照を返すよりも、変更可能な参照を与えている閉鎖取る:

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

ありがとう、これは問題を処理するかなりエレガントな方法です。私がここに見るのは、一般化可能性のみです。すなわち、クロージャは1つのパラメータしか受け入れません。いくつかのコンテキストが必要な場合、これはうまく機能しない可能性があります(特に、錆に過負荷がないため)。 – bge0

+0

関数ポインターではなくクロージャーとは、コンテキストを含めることができることを意味します。あなたは何ができないかもしれないかを示す例を挙げることができますか? –

+0

あなたは 'F:FnMut(&mut Params)'のどこに ''&mut Params' 'だけを取り込むものが正しいのでしょうか? 'F:FnMut(&mut Params)' **と** F:FnMut(&mut Params、&MyContext、i32)の場合、これには2つの異なるオーバーロードされた関数が必要です。できません(オプションの<>の束は少しありません。 – bge0

1

私は、コンパイラはあなたのケースで正しいと思います。

ここ2個の明らかなエラーがあります。

  1. layers_arc値はわずか1ブロックの最後まで生きて、そしてそれはデストラクタは参照カウンタをデクリメントし、多分全体の値をドロップしますです。または、いつでも他のスレッドで削除することができます。したがって、その内容へのポインタを返すことは違法です。

  2. Mutex::get_mutメソッドはArcから直接取得することはできませんが、が必要です。

コードを何とかリファクタリングする必要があります。たとえば、ベクトル内の個々のアイテムをArc<Mutex>で保護し、.clone()を使用して値で返すことができます。

+0

ありがとうございました@swizard。これも有効な答えです。ちょうど清潔のために以下のものと一緒に行くことに決めました。 – bge0

関連する問題