2017-02-04 7 views
2

私はRustを初めて使いました。学習の練習として、私はかつてC++で書いたシンプルなタイマー構造体を作成しようとしています。インタフェースと実装は次のようなものになります。私はこれが原因start関数内use of moved value: selfの誤差がある理由を理解デザインヘルプ:構造内のスレッディング

pub struct Timer { 
    handle: Option<std::thread::JoinHandle<()>>, 
    alive: bool, 
} 

impl Timer { 
    pub fn new() { 
     Timer { 
      handle: None, 
      alive: false, 
     } 
    } 

    pub fn start(&'static mut self) { 
     // Oops! How do I do this? 
     self.handle = Some(std::thread::spawn(move || { 
      self.alive = true; 
      self.loop() 
     })); 
    } 

    pub fn stop(&mut self) { 
     self.alive = false; 
     self.handle.unwrap().join() 
    } 

    pub fn loop(&self) { 
     // while alive 
    } 
} 

を、私は、私が何かするようデザインに私の構造体をなってるか思ったんだけどこれはうまくいくでしょう。私が考えることができるすべてのシナリオで、私はいつも二重の借りの状況があります。

私はインテリアの変更可能性についてもっと知る必要があると思っていますが、それ以上のウサギの穴を開ける前にデザインのガイダンスを聞いてみると思いました。

+0

あなたの 'struct'定義と' impl'は並んでいません。定義には1つのメンバ( 'handle')があり、' new'の実装には2つのメンバ( 'thread'と' alive')があります。私はそれが何であるべきかを推測しますが、コード内にあるものと一致すると良いでしょう。 –

+0

私はそれをもっと整理するつもりです、私は例を簡潔にするために多くのコードを簡略化しました。 – sholsapp

+0

はい、私はそれが本質にまで蒸留されているのを見ることができ、あなたが入れている努力に感謝します:) –

答えて

1

私はあなたがそれを動作させるのにかなり近いと思います。

は2つのだけハードルがあります。

  • thread::spawnあなたはこのデザイン

ソリューションは二つある中で共有するための共有の参照に

  • aliveloopを許可しません。

    • 参照がここで

    を禁じられているので、ontroller(Timer)とArcを使用して、2つの間の労働者(閉鎖)

  • シェア状態はでおもちゃにあなたのための最小限の例です。

    use std::{sync, thread, time}; 
    use std::sync::atomic::{AtomicBool, Ordering}; 
    
    pub struct Timer { 
        handle: Option<thread::JoinHandle<()>>, 
        alive: sync::Arc<AtomicBool>, 
    } 
    
    impl Timer { 
        pub fn new() -> Timer { 
         Timer { 
          handle: None, 
          alive: sync::Arc::new(AtomicBool::new(false)), 
         } 
        } 
    
        pub fn start<F>(&mut self, fun: F) 
         where F: 'static + Send + FnMut() ->() 
        { 
         self.alive.store(true, Ordering::SeqCst); 
    
         let alive = self.alive.clone(); 
    
         self.handle = Some(thread::spawn(move || { 
          let mut fun = fun; 
          while alive.load(Ordering::SeqCst) { 
           fun(); 
           thread::sleep(time::Duration::from_millis(10)); 
          } 
         })); 
        } 
    
        pub fn stop(&mut self) { 
         self.alive.store(false, Ordering::SeqCst); 
         self.handle 
          .take().expect("Called stop on non-running thread") 
          .join().expect("Could not join spawned thread"); 
        } 
    } 
    
    fn main() { 
        let mut timer = Timer::new(); 
        timer.start(|| println!("Hello, World!")); 
    
        println!("Feeling sleepy..."); 
        thread::sleep(time::Duration::from_millis(100)); 
    
        println!("Time for dinner!"); 
        timer.stop(); 
    } 
    

    I一度に1つずつ穴を開ける(つまり、あなたの例とは異なる1つの事を変更し、エラーメッセージをチェックして、その違いがどのように解決したかを理解しようとする)。遊び場で

    、それは私のために印刷:

    Feeling sleepy... 
    Hello, World! 
    Hello, World! 
    Hello, World! 
    Hello, World! 
    Hello, World! 
    Hello, World! 
    Hello, World! 
    Hello, World! 
    Hello, World! 
    Hello, World! 
    Time for dinner! 
    

    私は倍"Hello, World!"が表示されますの(1)の数に依存しないだろうと(2)"Feeling sleepy..."が最初に登場するけど。

    そしてのろわは、冗長Atomicです...私はちょっとget/setが利用可能SeqCst(強い順序)であったことを望みます。

  • +0

    ありがとうございます。私の例では、スレッド閉鎖が 'Timer'で追加の状態を操作できるようにしたいと明確に強調していませんでした。たとえば、ループ関数は、ユーザーが待機できる条件変数を通知したいと考えています。あなたのアプローチ(外部呼び出し可能コードを渡す)はまだ私にこれをさせません。それに関する追加的な考えは?私は今この例で遊んでいきます、もう一度ありがとうございます。 – sholsapp

    +0

    完全な透明性のために、私はこのクラスを再実装しています:https://github.com/sholsapp/gallocy/blob/master/gallocy/include/gallocy/consensus/timer.h – sholsapp

    +0

    私は持っているかのように感じます自己のものへの参照カウントが機能します... – sholsapp