Как позволить struct удерживать поток и уничтожать поток, как только он выходит из области видимости - PullRequest
0 голосов
/ 21 ноября 2019
struct ThreadHolder{
  state: ???
  thread: ???
}

impl ThreadHolder {
  fn launch(&mut self) {
    self.thread = ???
    // in thread change self.state
  }
}

#[test]
fn test() {
  let mut th = ThreadHolder{...};
  th.launch();
  // thread will be destroy as soon as th go out of scope
}

Я думаю, что есть над чем поработать, но я не знаю, как это написать.

Ответы [ 2 ]

2 голосов
/ 21 ноября 2019

То, что вы хотите, настолько просто, что вам даже не нужно, чтобы оно было изменяемым каким-либо образом, и тогда становится простым делить его между потоками, если вы не хотите сбросить его. Вы сказали, что по той или иной причине вам необходимо покинуть поток, поэтому я предполагаю, что вас это не волнует.

Вместо этого вы можете опрашивать его каждый тик (большинство игр запускаются по тикам, поэтому яне думаю, что возникнут какие-либо проблемы с его реализацией).

Я приведу пример, который использует сон, так что это не самая точная вещь, это болезненно очевидно в последнюю секунду, но я не пытаюсьВ любом случае, делайте свою работу за вас, в Интернете достаточно ресурсов, которые помогут вам справиться с этим.

Вот так:

use std::{
    sync::Arc,
    thread::{self, Result},
    time::{Duration, Instant},
};

struct Timer {
    end: Instant,
}

impl Timer {
    fn new(duration: Duration) -> Self {
        // this code is valid for now, but might break in the future
        // future so distant, that you really don't need to care unless
        // you let your players draw for eternity
        let end = Instant::now().checked_add(duration).unwrap();

        Timer { end }
    }

    fn left(&self) -> Duration {
        self.end.saturating_duration_since(Instant::now())
    }

    // more usable than above with fractional value being accounted for
    fn secs_left(&self) -> u64 {
        let span = self.left();

        span.as_secs() + if span.subsec_millis() > 0 { 1 } else { 0 }
    }
}

fn main() -> Result<()> {
    let timer = Timer::new(Duration::from_secs(10));
    let timer_main = Arc::new(timer);

    let timer = timer_main.clone();
    let t = thread::spawn(move || loop {
        let seconds_left = timer.secs_left();
        println!("[Worker] Seconds left: {}", seconds_left);

        if seconds_left == 0 {
            break;
        }

        thread::sleep(Duration::from_secs(1));
    });

    loop {
        let seconds_left = timer_main.secs_left();
        println!("[Main] Seconds left: {}", seconds_left);

        if seconds_left == 5 {
            println!("[Main] 5 seconds left, waiting for worker thread to finish work.");
            break;
        }

        thread::sleep(Duration::from_secs(1));
    }

    t.join()?;

    println!("[Main] worker thread finished work, shutting down!");

    Ok(())
}

Кстати, такого рода реализация не будетбыть другим на любом другом языке, поэтому, пожалуйста, не вините в этом Руста. Это не самый простой язык, но он предоставляет более чем достаточно инструментов для создания чего угодно с нуля, если приложить к этому усилия.

Goodluck:)

0 голосов
/ 22 ноября 2019

Я думаю, у меня все получилось

use std::sync::{Arc, Mutex};
use std::thread::{sleep, spawn, JoinHandle};
use std::time::Duration;

struct Timer {
    pub(crate) time: Arc<Mutex<u32>>,
    jh_ticker: Option<JoinHandle<()>>,
}

impl Timer {
    fn new<T>(i: T, duration: Duration) -> Self
    where
        T: Iterator<Item = u32> + Send + 'static,
    {
        let time = Arc::new(Mutex::new(0));

        let arc_time = time.clone();
        let jh_ticker = Some(spawn(move || {
            for item in i {
                let mut mg = arc_time.lock().unwrap();
                *mg = item;
                drop(mg); // needed, otherwise this thread will always hold lock
                sleep(duration);
            }
        }));

        Timer { time, jh_ticker }
    }
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.jh_ticker.take().unwrap().join();
    }
}

#[test]
fn test_timer() {
    let t = Timer::new(0..=10, Duration::from_secs(1));
    let a = t.time.clone();
    for _ in 0..100 {
        let b = *a.lock().unwrap();
        println!("{}", b);
        sleep(Duration::from_millis(100));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...