2017-03-05 13 views
0

こんにちは、私はかなり簡単なテストケース で寿命が問題になりました。コンパイラが私に言っていることを理解できないようです。 以下のコードは、Rustプレイグラウンドにペーストします。寿命のエラー解決方法がわかりません

コードの考え方は、Elementがパイプラインにまとめられているということです。データは最終的に1つの要素を次の要素に渡します。各段は前の段からの入力を受けて次の段にデータを送る(rx, tx)対を有する。 をSyncとマークすることができるので、Elementは1度にデータの一部を処理します。

エラーは以下のとおりです。

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements 
    --> <anon>:56:18 
    | 
56 |   for e in self.elements { 
    |     ^^^^^^^^^^^^^ 
    | 
note: first, the lifetime cannot outlive the lifetime 'a as defined on the body at 53:53... 
    --> <anon>:53:54 
    | 
53 |  pub fn run(&self) -> Vec<thread::JoinHandle<()>> { 
    |             ^
note: ...so that expression is assignable (expected std::vec::Vec<Box<&Element>>, found std::vec::Vec<Box<&'a Element + 'a>>) 
    --> <anon>:56:18 
    | 
56 |   for e in self.elements { 
    |     ^^^^^^^^^^^^^ 
    = note: but, the lifetime must be valid for the static lifetime... 
note: ...so that the type `[[email protected]<anon>:62:41: 64:15 e:Box<&Element>, sender:std::sync::Arc<std::sync::Mutex<std::sync::mpsc::SyncSender<(std::string::String, std::string::String)>>>, receiver:std::sync::Arc<std::sync::Mutex<std::sync::mpsc::Receiver<(std::string::String, std::string::String)>>>]` will meet its required lifetime bounds 
    --> <anon>:62:27 
    | 
62 |    handles.push(thread::spawn(move || { 
    |       ^^^^^^^^^^^^^ 

私がそのように彼らはPipelineとして一緒に出回っ 固執コンパイラに伝えるべきではありませんElement sは &'a Elementのように定義されているようで混乱していた最初のエラー?

Vec<thread::JoinHandle<()>>は生涯に依存していると言われています。'a?私はそれをどのように伝達するかわかりません。

私は最初の2つを修正した後、3番目の方が意味をなされることを望みます。現時点で私はそれが何を伝えているのか分かりません。前のエラーまたは警告にコンテキストを追加コンパイラによって報告さ

use std::sync::{Arc, Mutex}; 
use std::thread; 
use std::result::Result; 
use std::sync::mpsc::{SyncSender, Receiver, sync_channel}; 

pub trait Element: Send + Sync { 
    fn run(&self, output: Arc<Mutex<SyncSender<i32>>>, 
        input: Arc<Mutex<Receiver<i32>>>); 
} 

pub struct TestElement {} 

impl TestElement { 
    pub fn new() -> Self { 
     TestElement {} 
    } 
} 

impl Element for TestElement { 
    fn run(&self, output: Arc<Mutex<SyncSender<i32>>>, 
        input: Arc<Mutex<Receiver<i32>>>) { 
     println!("Hello"); 
    } 
} 

pub struct Pipeline<'a> { 
    elements: Vec<Box<&'a Element>>, 
} 

impl<'a> Pipeline<'a> { 
    pub fn new(name: String) -> Self { 
     Pipeline { 
      elements: Vec::new(), 
     } 
    } 

    pub fn run(&self) -> Vec<thread::JoinHandle<()>> { 
     let mut handles = Vec::with_capacity(self.elements.len()); 

     for e in self.elements { 
      let channel = sync_channel::<i32>(1000); 
      let sender = Arc::new(Mutex::new(channel.0)).clone(); 
      let receiver = Arc::new(Mutex::new(channel.1)).clone(); 

      handles.push(thread::spawn(move || { 
       e.run(sender, receiver); 
      })); 
     } 

     handles 
    } 
} 

fn main() { 
    let mut test_element = TestElement::new(); 
    let mut pipeline = Pipeline::new("example pipeline".to_string()); 

    let handles = pipeline.run(); 
} 
+0

あなたはさらに、あなたのコードを簡素化できますか?それはまだかなり大きなコードであり、答えが簡単で、小さなコードを扱うときだけ理解しやすくなります。ありがとう:) –

+0

私は少しサイズを縮小しようとしました。私はより多くを減らすことができますが、それはいくつかのエラーを取り除くだろうと私は彼らが別のエラーであるかどうか私は知らないかどうかは、1つの修正に関連するかどうかは不明でした。どう思いますか ? –

+0

なぜあなたは 'Box <&'a Element>'を使用していますか? 'Box'はすでにヒープが割り当てられており、基本的にはポインタにすぎないので、' Box 'で十分です。これはまたあなたの生涯の問題を解決するでしょう(しかし他の問題については光を照らす)。また、生成されたスレッドは他のものより長く存続する可能性があるので、 'Pipeline :: run()'で生成されたスレッドは 'Pipeline'オブジェクトより長く存続します。これは答えではありませんが、正しい方向への微妙な動きです。 –

答えて

1

note。別のエラーではありません。エラーを修正すると、メモが消えてしまいます。

残念ながら、このエラーメッセージはあまり明確ではありません。問題は、タイプBox<&'a Element>のを、thread::spawnに渡されるクロージャに移動しようとしていますが、thread::spawnには、'staticの有効期間に有効なクロージャが必要です。すなわち、それは'staticより短い参照を含まない(そして'staticは利用可能な最も長い存続時間であり、それはプログラム全体の持続時間に対応する)。 'a'staticと等しくなることは保証されていないため、エラーです。

Element参照が解放された後にスレッドが実行を継続する可能性があるため、コードが無効です。

可能な解決策の1つは、elementsベクター内の参照を使用しないことです。使用Vec<Box<Element>>。後で要素を再利用する必要がない場合にのみ機能します。

もう1つの方法は、単純参照の代わりにスレッドセーフ参照カウンタ(Arc)を使用する方法です。これにより、生涯の懸念は排除されますが、ランタイムオーバーヘッドが少し発生します。

最後に、crossbeam~spawnscopedスレッドを使用します。このオプションを使用すると、引き続き参照を使用できます。これではできないことの1つは、スコープが終了する前にジョインハンドルを戻すことです。あなたはまだPipeline::runから参加ハンドルを返すことができますが、scopeが返す前にcrossbeamがすべてのスレッドに参加します。

ヒストリカルノート:錆が1.0に到達する直前に、標準ライブラリのスコープのスレッドの実装があるように使用。しかし、その代わりにスコープのためのクロージャを使用して、それは単にJoinHandleを返すと、この実装の安全性は、JoinHandleにデストラクタを呼び出すプログラムに依存していました。デストラクタは、適切な時間に実行されなかった場合(例えば、あなたがmem::forgetと呼ばれる)、その後、スレッドが実行し続けるだろうし、潜在的に割り当て解除オブジェクトを参照します。 crossbeamまだデストラクタが呼び出されているに依存しているが、図書館の利用者がScopeの所有権を取得することはできませんように、ライブラリはデストラクタが実行されることを保証することができますので、それは、書かれています。

+0

最後にありがとう、私はクロスビームを使用しました。複数のエラーが私を混乱させていました。彼らは、標準ライブラリにクロスビームを再導入することはできません 恥を知れ。 –

+0

彼らは確かに 'crossbeam'の機能を標準ライブラリに導入することができますが、外部ライブラリとしての新しい機能を開発することにはいくつかの利点があります。標準ライブラリに導入された新しい機能が最初に_unstable_として導入されたため、著者は初期の段階でAPIを変更する柔軟性が増し、夜間コンパイラを使用するユーザーだけが使用できるようになりました。 –

関連する問題