防止在并发操作中多次借用

时间:2018-08-09 08:44:00

标签: concurrency rust

我正在尝试并行化一个无限脉冲响应滤波器,表示为双二阶级联:

An infinite impulse response filter, represented as a cascade of biquads

输入数据分为5个块(列)。 IIR具有3个二元级联(行)。要运行biquad(这些块之一),必须已计算了该块紧邻左侧和下方的数据。块中的数字表示该块可能的最早计算顺序。

我正在使用mpscscoped_threadpool尝试构建一种算法,该算法可以并行计算尽可能多的块。

extern crate scoped_threadpool;

use scoped_threadpool::Pool;
use std::sync::mpsc::channel;

fn main() {}

pub struct BiQuad {}

impl BiQuad {
    pub fn new() -> BiQuad {
        BiQuad {}
    }

    #[inline]
    pub fn apply(&mut self, _data: &mut [f64]) {}
}

pub struct Filter {
    biquads: Vec<BiQuad>,
}

impl Filter {
    pub fn new() -> Filter {
        Filter {
            biquads: Vec::new(),
        }
    }

    pub fn add_biquad(&mut self, biquad: BiQuad) {
        self.biquads.push(biquad);
    }

    pub fn apply_concurrently(&mut self, data: &mut [f64], threads: usize) {
        apply_concurrently_internal(&mut self.biquads, data, threads);
    }
}

fn apply_concurrently_internal(biquads: &mut [BiQuad], data: &mut [f64], threads: usize) {
    if !biquads.is_empty() {
        let mut pool = Pool::new(threads as u32);
        let (tx, rx) = channel();
        let tx2 = tx.clone();
        let chunk_size = data.len() / threads;

        tx.send((0, 0, data.split_at_mut(chunk_size), biquads.split_at_mut(1)));

        pool.scoped(|scope| {
            loop {
                match rx.recv() {
                    Ok((
                        biquad,
                        block,
                        (chunk_data, remaining),
                        (current_biquad, cascading_biquads),
                    )) => {
                        let inner_tx = tx2.clone();

                        println!("got here: {} - {}", biquad, block);

                        scope.execute(move || {
                            current_biquad[0].apply(chunk_data);

                            //Move horizontally (through data)
                            inner_tx.send((
                                biquad,
                                block + 1,
                                remaining.split_at_mut(chunk_size),
                                (current_biquad, cascading_biquads),
                            ));

                            //Move vertically (cascade)
                            inner_tx.send((
                                biquad + 1,
                                block,
                                (chunk_data, &mut []),
                                cascading_biquads.split_at_mut(1),
                            ));
                        });
                    }
                    Err(_) => break,
                }
            }
        });
    }
}

playground

计算完第一个块之后,我想表示有2个块可用(1,0和0,1)。双向二阶切片不能同时发送到两个块,这是借用冲突:

error[E0499]: cannot borrow `*cascading_biquads` as mutable more than once at a time
  --> src/main.rs:77:33
   |
69 |                                 (current_biquad, cascading_biquads),
   |                                                  ----------------- first mutable borrow occurs here
...
77 |                                 cascading_biquads.split_at_mut(1),
   |                                 ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
78 |                             ));
79 |                         });
   |                         - first borrow ends here

此外,正如所写的,没有什么可以阻止块2,2从第3而不是至少第4执行。

这是我可以用Rust的(无所畏惧!)并发功能很好地解决的问题吗?是否有任何模式可用于同时运行的操作既共享数据又相互依赖的情况下解决?

0 个答案:

没有答案