Multithreading 运行生成线程的可中断Rust程序

Multithreading 运行生成线程的可中断Rust程序,multithreading,rust,signals,Multithreading,Rust,Signals,我试图编写一个程序,生成一堆线程,然后在最后加入线程。我希望它是可中断的,因为我的计划是使它成为UNIX服务中持续运行的程序 其思想是worker\u pool将包含已生成的所有线程,因此可以随时调用terminate来收集它们 我似乎找不到一种方法来利用chan_select板条箱来实现这一点,因为这需要我首先生成一个线程来生成我的子线程,一旦我这样做了,我就不能再在中断时加入线程时使用worker_pool变量,因为它必须被移出主循环。如果在中断中注释掉终止工作进程的行,它将编译 我有点沮丧

我试图编写一个程序,生成一堆线程,然后在最后加入线程。我希望它是可中断的,因为我的计划是使它成为UNIX服务中持续运行的程序

其思想是
worker\u pool
将包含已生成的所有线程,因此可以随时调用
terminate
来收集它们

我似乎找不到一种方法来利用chan_select板条箱来实现这一点,因为这需要我首先生成一个线程来生成我的子线程,一旦我这样做了,我就不能再在中断时加入线程时使用
worker_pool
变量,因为它必须被移出主循环。如果在中断中注释掉终止工作进程的行,它将编译

我有点沮丧,因为这在C语言中很容易实现。我可以设置一个静态指针,但当我在Rust中尝试这样做时,我会得到一个错误,因为我正在为线程使用一个向量,并且我不能在静态中初始化为空向量。我知道在中断代码中加入工作者是安全的,因为执行在这里停止,等待信号

也许有更好的方法来处理信号,或者我错过了一些我能做的事情

错误和代码如下所示:

MacBook8088:video\u摄取pjohnson$cargo运行
编译视频_摄取v0.1.0(file:///Users/pjohnson/projects/video_ingest)
错误[E0382]:使用移动的值:`worker\u pool`
-->src/main.rs:30:13
|
24 |线程::生成(移动| |运行(sdone和mut worker_池));
|------此处的值已移动(进入闭包)
...
30 |工人池终止();
|^^^^^^^^^^^^^移动后此处使用的值
:42:47:43:23注:在此chan_的扩展中选择!(定义见)
src/main.rs:27:5:35:6注:在chan_的扩展中选择!(定义见)
|
=注意:发生移动是因为'worker\u pool'的类型为'video\u insect::WorkerPool',而该类型不实现'Copy'特性
梅因
#[宏使用]
陈文杰;
外部板条箱信号;
外部板条箱视频摄取;
使用chan_信号::信号;
使用视频摄取::WorkerPool;
使用std::线程;
使用std::ptr;
///
///开始处理
/// 
fn main(){
让mut worker_pool=WorkerPool{join_handles:vec![]};
//当操作系统发送INT或TERM信号时,Signal获取一个值。
let signal=chan_signal::notify(&[signal::INT,signal::TERM]);
//我们的工作完成后,在“sdone”上发送哨兵值。
let(sdone,rdone)=chan::sync(0);
//运行工作。
线程::spawn(移动| |运行(sdone和mut worker_池));
//等待信号或工作完成。
陈选{
signal.recv()->signal=>{
println!(“接收信号:{:?}”,信号);
worker_pool.terminate();//{
println!(“程序正常完成”);
}
}
}
fn运行(sdone:chan::发送方、工作者池:&mut工作者池){
环路{
worker_pool.inset();
worker_pool.terminate();
}
}
图书馆
extern板条箱libc;
使用std::线程;
使用std::thread::JoinHandle;
使用std::os::unix::thread::JoinHandleExt;
使用libc::pthread_join;
使用libc::c_void;
使用std::ptr;
使用std::time::Duration;
pub结构WorkerPool{
pub join_句柄:Vec
}
impl-WorkerPool{
///
///实际摄取量是多少
///
发布fn摄取(&M自我){
//以9个线程为例。
因为我在0..10{
self.join\u handles.push(
线程::生成(移动| |{
//获取视频
println!(“获取线程{}的视频”,i);
线程::睡眠(持续时间::新建(5,0));
})
);
}
}
///
///连接所有线程
///
发布fn终止(&mut self){
println!((“总句柄:{}”,self.join_handles.len());
用于句柄in和self.join\u句柄{
println!(“连接线程…”);
不安全{
让mut state_ptr:*mut*mut c_void=0为*mut*mut c_void;
pthread_join(handle.as_pthread_t(),state_ptr);
}
}
self.join_handles=vec![];
}
}
terminate
可以随时调用以收集它们

我不想停止线程;我想通过
join
收集线程。我同意停止线程不是一个好主意

这两条语句对我来说毫无意义。你只能在线程完成后加入线程。“可中断”和“随时”这两个词意味着你可以尝试在线程仍在进行某些处理时停止线程。你想要哪种行为

如果您希望能够停止已部分完成的线程,则必须增强代码以检查其是否应提前退出。这通常会因为您正在进行一些无法控制的大型计算而变得复杂。理想情况下,您可以将其分为多个块,并经常检查退出标志。例如,使用vide工作时,你可以检查每一帧。然后响应延迟大约是处理一帧的时间

这在C语言中很容易做到

这很容易出错。例如,当前提供的代码试图在没有任何同步的情况下从两个不同的线程对池执行变异。这肯定会导致代码损坏,难以调试

//以9个线程为例

0..10
创建10个线程


无论如何,缺少的知识似乎是和。
Arc
允许在线程之间共享单个项目的所有权,
Mutex
允许线程之间的运行时可变借用

#[macro_use]
extern crate chan;
extern crate chan_signal;

use chan_signal::Signal;
use std::thread::{self, JoinHandle};
use std::sync::{Arc, Mutex};

fn main() {
    let worker_pool = Arc::new(Mutex::new(WorkerPool::new()));

    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);

    let (work_done_tx, work_done_rx) = chan::sync(0);

    let worker_pool_clone = worker_pool.clone();
    thread::spawn(move || run(work_done_tx, worker_pool_clone));

    // Wait for a signal or for work to be done.
    chan_select! {
        signal.recv() -> signal => {
            println!("received signal: {:?}", signal);
            let mut pool = worker_pool.lock().expect("Unable to lock the pool");
            pool.terminate();
        },
        work_done_rx.recv() => {
            println!("Program completed normally.");
        }
    }
}

fn run(_work_done_tx: chan::Sender<()>, worker_pool: Arc<Mutex<WorkerPool>>)  {
    loop {
        let mut worker_pool = worker_pool.lock().expect("Unable to lock the pool");
        worker_pool.ingest();
        worker_pool.terminate();
    }
}

pub struct WorkerPool {
    join_handles: Vec<JoinHandle<()>>,
}

impl WorkerPool {
    pub fn new() -> Self {
        WorkerPool {
            join_handles: vec![],
        }
    }

    pub fn ingest(&mut self) {
        self.join_handles.extend(
            (0..10).map(|i| {
                thread::spawn(move || {
                    println!("Getting videos for thread {}", i);
                })
            })
        )
    }

    pub fn terminate(&mut self) {
        for handle in self.join_handles.drain(..) {
            handle.join().expect("Unable to join thread")
        }
    }
}

欢迎使用Stack Overflow!您是否已经理解为什么停止任意线程是一个(不是语言特定的问题)?除此之外,
#[macro_use]
extern crate chan;
extern crate chan_signal;

use chan_signal::Signal;
use std::thread::{self, JoinHandle};
use std::sync::{Arc, Mutex};

fn main() {
    let worker_pool = Arc::new(Mutex::new(WorkerPool::new()));

    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);

    let (work_done_tx, work_done_rx) = chan::sync(0);

    let worker_pool_clone = worker_pool.clone();
    thread::spawn(move || run(work_done_tx, worker_pool_clone));

    // Wait for a signal or for work to be done.
    chan_select! {
        signal.recv() -> signal => {
            println!("received signal: {:?}", signal);
            let mut pool = worker_pool.lock().expect("Unable to lock the pool");
            pool.terminate();
        },
        work_done_rx.recv() => {
            println!("Program completed normally.");
        }
    }
}

fn run(_work_done_tx: chan::Sender<()>, worker_pool: Arc<Mutex<WorkerPool>>)  {
    loop {
        let mut worker_pool = worker_pool.lock().expect("Unable to lock the pool");
        worker_pool.ingest();
        worker_pool.terminate();
    }
}

pub struct WorkerPool {
    join_handles: Vec<JoinHandle<()>>,
}

impl WorkerPool {
    pub fn new() -> Self {
        WorkerPool {
            join_handles: vec![],
        }
    }

    pub fn ingest(&mut self) {
        self.join_handles.extend(
            (0..10).map(|i| {
                thread::spawn(move || {
                    println!("Getting videos for thread {}", i);
                })
            })
        )
    }

    pub fn terminate(&mut self) {
        for handle in self.join_handles.drain(..) {
            handle.join().expect("Unable to join thread")
        }
    }
}
use std::sync::atomic::{AtomicBool, Ordering};

fn main() {
    let worker_pool = WorkerPool::new();

    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);
    let please_stop = Arc::new(AtomicBool::new(false));

    let threads_please_stop = please_stop.clone();
    let runner = thread::spawn(|| run(threads_please_stop, worker_pool));

    // Wait for a signal
    chan_select! {
        signal.recv() -> signal => {
            println!("received signal: {:?}", signal);
            please_stop.store(true, Ordering::SeqCst);
        },
    }

    runner.join().expect("Unable to join runner thread");
}

fn run(please_stop: Arc<AtomicBool>, mut worker_pool: WorkerPool)  {
    while !please_stop.load(Ordering::SeqCst) {
        worker_pool.ingest();
        worker_pool.terminate();
    }
}