2017-02-04 5 views
2

Я новичок в Rust. В качестве учебного упражнения я пытаюсь написать простую структуру таймера, которую я когда-то писал на C++. Интерфейс и реализация выглядит следующим образом:Помощь в дизайне: нарезка внутри структуры

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 
    } 
} 

Я понимаю, почему это ошибка из-за use of moved value: self в функции start, но мне интересно, как я должен дизайн мой, так что-структуру что-то как это будет работать. В каждом сценарии, о котором я могу думать, у меня всегда будет ситуация с двойным заимствованием.

У меня есть подозрение, что мне нужно больше узнать о внутренней изменчивости, но подумал, что я попрошу совета по проектированию, прежде чем спускать больше кроличьих отверстий.

+0

Ваше 'struct' определение и' impl' не выстраиваются в линию. В определении у него есть один член ('handle'), а в реализации' new' он имеет два члена ('thread' и' alive'). Я догадываюсь, что это должно быть, но было бы лучше, если бы они соответствовали тому, что у вас есть в коде. –

+0

Я поработаю над его очисткой больше, я упростил много кода, чтобы сохранить пример кратким. – sholsapp

+0

Да, я вижу, что он перегонял по своей сути, и я ценю усилия, которые вы вложили :) Просто пытаясь разобраться в этом. –

ответ

1

Я думаю, вы очень близки к тому, чтобы заставить его работать.

Есть только два препятствия:

  • thread::spawn не разрешить ссылки ОБМЕН
  • alive и loop для Вас принять участие в этом проекте

Раствор два раза:

  • разделить вещи между c ontroller (Timer) и работник (закрытие)
  • доля государства между ними с использованием Arc поскольку ссылки запрещены

Вот минимальный пример для вас, чтобы играть с:

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 приглашаем вас пробивать дыры в нем по одному (т. е. изменить одну вещь, отличную от вашего примера, проверить сообщение об ошибке и попытаться понять, как разность решила ее).

На детской площадке, напечатанное для меня:

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! 

Хотя я бы не полагаться на (1) число раз "Hello, World!" появляется и (2) "Feeling sleepy..." появляется первый.

И проклятый, это Atomic многословным ... Я вроде хотел было get/set с SeqCst (сильнее заказа) доступны.

+0

Спасибо. В моем примере не было четко подчеркнуто, что я хотел бы, чтобы закрытие потока могло работать над дополнительным состоянием в «Таймер». Например, функция цикла хотела бы сигнализировать переменную состояния, которую пользователи могут ждать.Ваш подход (который проходит во внешнем вызываемом) все еще не позволяет мне это делать. Какие-нибудь дополнительные мысли по этому поводу? Теперь я продолжу играть с этим примером, спасибо еще раз. – sholsapp

+0

Для полной прозрачности я возился, переопределяя этот класс: https://github.com/sholsapp/gallocy/blob/master/gallocy/include/gallocy/consensus/timer.h – sholsapp

+0

Похоже, если бы я мог подсчет ссылок на самообслуживание будет работать ... – sholsapp