线程处于休眠状态时跳过循环的一部分

时间:2016-08-29 04:13:21

标签: multithreading rust

我想在循环中运行两部分代码。有时我需要让循环'睡眠',使每次迭代跳过第二部分。循环应该在一段时间后停止休眠(例如使用调用thread::sleep的线程)。我该如何做到这一点?

use std::thread;

let mut sleeping = false;
let mut handle = thread::spawn(|| {});

loop {
    part_1();

    if sleeping {
        continue;
    }

    part_2();

    if some_condition {
        sleeping = true;
        handle = thread::spawn(|| thread::sleep_ms(100));
    }
}

在此示例中,如果满足条件,则会跳过part_2次调用以进行一定量的迭代。我的用例是继续在游戏中运行图形更新,同时冻结游戏的逻辑(例如倒计时器)。

2 个答案:

答案 0 :(得分:2)

不需要线程开销,甚至不需要睡眠。只需跟踪延迟执行代码的时间,直到:

dll

虽然我可能在这里避免使用use std::time::{Duration, Instant}; fn part_1() {} fn part_2() {} fn some_condition() -> bool { false } fn main() { let mut sleep_until = None; loop { part_1(); if let Some(until) = sleep_until { if until > Instant::now() { continue; } } part_2(); if some_condition() { let now = Instant::now(); let until = now + Duration::from_millis(500); sleep_until = Some(until); } } } ,而是将逻辑嵌入:

continue

注意在一个案例中我使用use std::time::{Duration, Instant}; fn perform_physics_calculation() {} fn perform_graphics_render() {} fn main() { let mut next_graphics_update = Instant::now(); let graphics_delay = Duration::from_millis(500); loop { let now = Instant::now(); perform_physics_calculation(); if next_graphics_update <= now { perform_graphics_render(); next_graphics_update = now + graphics_delay; } } } 而在另一个案例中我只使用Option<Instant>;两种情况都有意义。

答案 1 :(得分:1)

sleeping变量转换为引用计数的原子布尔值,以便您可以在休眠线程上重置它。

use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;

fn part_1() {}
fn part_2() {}
fn some_condition() -> bool { false }

fn main() {
    let sleeping = Arc::new(AtomicBool::new(false));
    let mut handle = None;

    loop {
        part_1();

        if sleeping.load(Ordering::Acquire) {
            continue;
        }

        part_2();

        if some_condition() {
            sleeping.store(true, Ordering::Release);
            let sleeping_clone = sleeping.clone();
            handle = Some(thread::spawn(move || {
                thread::sleep(Duration::from_millis(100));
                sleeping_clone.store(false, Ordering::Release);
            }));
        }
    }
}