如何在Rust中自重启线程?

qgelzfjb  于 2023-04-30  发布在  其他
关注(0)|答案(1)|浏览(145)

我对生 rust 还是个新手。我有下面的代码,它产生了一个线程,并在该线程中使用nokhwa crate创建了一个相机线程:

let mut handle_vec = vec![]; // JoinHandles will go in here
let handle = thread::spawn(move || {
    let cameras = query(ApiBackend::Auto).unwrap();
    if cameras.len() > 0 {
        let requested: RequestedFormat =
            RequestedFormat::new::<RgbFormat>(RequestedFormatType::AbsoluteHighestFrameRate);
        // make the camera
        let mut camera = match CallbackCamera::new(CameraIndex::Index(0), requested, move |buf| {
            let val = percentile(&buf.decode_image::<LumaFormat>().unwrap(), 90);
            hists_clone.store(val, Ordering::Relaxed);
        }) {
            Ok(val) =>{
                val
            },
            Err(err) => {
                eprint!("{}", err);
                return;
            }
        };
        camera.open_stream().unwrap();
        loop {
        }
    }
});
handle_vec.push(handle); // save the handle so we can call join on it outside of the loop

loop {
    more code...
    //TODO HERE: check thread and restart if dead?
}

目标是创建一个回调相机对象,并在出错时进行恢复。如果出现错误,我想简单地重新启动线程(以便我可以再试一次)。有时相机可能会断开连接,导致错误,其他时候可能一开始就没有连接。我该怎么做呢?更好的方法是什么?

j7dteeu8

j7dteeu81#

你的例子非常复杂,使用了很多未定义的函数,所以让我把它简化为一个minimal reproducible example

use std::{
    thread::{self, sleep},
    time::Duration,
};

#[derive(Debug)]
struct Camera;

fn init_camera() -> Result<Camera, String> {
    sleep(Duration::from_millis(200));

    let val: u8 = rand::random();
    if val < 50 {
        Ok(Camera)
    } else {
        Err("Camera failed to initialize!".to_string())
    }
}

fn main() {
    let mut handle_vec = vec![]; // JoinHandles will go in here
    let handle = thread::spawn(move || {
        let camera = match init_camera() {
            Ok(val) => val,
            Err(err) => {
                eprintln!("{}", err);
                return;
            }
        };

        println!("We got a camera: {:?}", camera);

        // ... do something with camera
    });
    handle_vec.push(handle); // save the handle so we can call join on it outside of the loop

    loop {
        //more code...
        //TODO HERE: check thread and restart if dead?
    }
}
Camera failed to initialize!
... stuck forever inside of loop ...

现在有多种方法来解决这个问题。
最简单的方法是在线程的内循环

use std::{
    thread::{self, sleep},
    time::Duration,
};

#[derive(Debug)]
struct Camera;

fn init_camera() -> Result<Camera, String> {
    sleep(Duration::from_millis(200));

    let val: u8 = rand::random();
    if val < 50 {
        Ok(Camera)
    } else {
        Err("Camera failed to initialize!".to_string())
    }
}

fn main() {
    let mut handle_vec = vec![]; // JoinHandles will go in here
    let handle = thread::spawn(move || {
        let camera = loop {
            match init_camera() {
                Ok(val) => break val,
                Err(err) => {
                    eprintln!("{}", err);
                    eprintln!("Retrying ...");
                }
            }
        };

        println!("We got a camera: {:?}", camera);

        // ... do something with camera
    });
    handle_vec.push(handle); // save the handle so we can call join on it outside of the loop

    for handle in handle_vec {
        handle.join().unwrap();
    }
}
Camera failed to initialize!
Retrying ...
Camera failed to initialize!
Retrying ...
We got a camera: Camera

如果你必须能够处理panic() s以及,你可以双重产卵:

use std::{
    thread::{self, sleep},
    time::Duration,
};

#[derive(Debug)]
struct Camera;

fn init_camera() -> Result<Camera, String> {
    sleep(Duration::from_millis(200));

    let val: u8 = rand::random();
    if val < 20 {
        Ok(Camera)
    } else if val < 100 {
        // Add chance that it panics
        panic!("Camera initialization panic!");
    } else {
        Err("Camera failed to initialize!".to_string())
    }
}

// Extracted into separate function because the nesting
// got too ridiculous
fn camera_thread() -> Result<(), String> {
    let camera = init_camera()?;
    println!("We got a camera: {:?}", camera);

    // ... do something with camera

    Ok(())
}

fn main() {
    let mut handle_vec = vec![]; // JoinHandles will go in here
    let handle = thread::spawn(|| loop {
        match thread::spawn(camera_thread).join() {
            Ok(Ok(())) => break,
            Ok(Err(err)) => eprintln!("Thread failed: {:?}", err),
            Err(err) => eprintln!("Thread panicked: {:?}", err.downcast_ref::<&str>().unwrap()),
        }
        eprintln!("Retrying ...");
    });
    handle_vec.push(handle); // save the handle so we can call join on it outside of the loop

    for handle in handle_vec {
        handle.join().unwrap();
    }
}
Thread failed: "Camera failed to initialize!"
Retrying ...
Thread failed: "Camera failed to initialize!"
Retrying ...
Thread failed: "Camera failed to initialize!"
Retrying ...
thread '<unnamed>' panicked at 'Camera initialization panic!', src/main.rs:17:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Thread panicked: "Camera initialization panic!"
Retrying ...
Thread failed: "Camera failed to initialize!"
Retrying ...
We got a camera: Camera

当然还有很多方法,但这些都是我想到的。
但回答你最初的问题不,线程没有办法重新启动自己。你需要在线程内部或外部的某个地方使用loop

相关问题