在由互斥锁

时间:2019-03-01 09:53:02

标签: rust

我有一个带有两个向量的结构,该结构在Arc<Mutex<TwoArrays>>中通过函数传递。

pub struct TwoArrays {
    pub a: Vec<i32>,
    pub b: Vec<i32>,
}

fn add_arrays(mut foo: Arc<Mutex<TwoArrays>>) {
    let mut f = foo.lock().unwrap();
    //Loop A: compiles
    for i in 0..f.a.len() {
        for j in 0..f.b.len() {
            f.b[j] += f.a[i];
        }
    }
    //Loop B: does not compile
    for i in f.a.iter() {
        for j in 0..f.b.len() {
            f.b[j] += i;
        }
    }
}

当我创建一个使用迭代器的循环,并在其中编写另一个循环(循环B)时,编译器会抱怨:

error[E0502]: cannot borrow `f` as mutable because it is also borrowed as immutable

循环A编译。

  • 为什么对f有不可变的借位?
  • 我可以使其仅借用每个数组吗?也就是说,f.b的可变借用和f.a的可变借用?
  • 当我直接通过TwoArrays时为什么没有发生这种情况?仅当我以Arc<Mutex<TwoArrays>>
  • 的身份通过时才会发生

2 个答案:

答案 0 :(得分:4)

解开LockResult时,您会得到MutexGuard,直接得到TwoArrays不是。您可以像使用TwoArrays一样使用它,因为它实现了DerefDerefMut

当您尝试编写2个循环时,尝试同时使用derefderef_mut:这是不可能的:

pub struct TwoArrays {
    pub a: Vec<i32>,
    pub b: Vec<i32>,
}

fn add_arrays(mut foo: Arc<Mutex<TwoArrays>>) {
    let mut f = foo.lock().unwrap();

    //Loop B: does not compile
    for i in f.a.iter() {
          //  ^~~~~~~~~~~~~~~~~~~ Implicit call to `deref` here.
        for j in 0..f.b.len() {
          //         ^~~~~~~~~~~~ Another implicit call to `deref` here.
            f.b[j] += i;
          // ^~~~~~~~~~~~~~~~~~~~ Implicit call to `deref_mut` here.
        }
    }
}

如果您在执行循环之前deref_mut一次,则一切正常:

use std::{sync::{Arc, Mutex}, ops::DerefMut};

pub struct TwoArrays {
    pub a: Vec<i32>,
    pub b: Vec<i32>,
}

fn add_arrays(foo: &mut Arc<Mutex<TwoArrays>>) {
    let mut mutex_guard = foo.lock().unwrap();
    let real_two_arrays = mutex_guard.deref_mut();

    for i in &mut real_two_arrays.a {
        for j in &real_two_arrays.b {
            *i += *j;
        }
    }
}

答案 1 :(得分:1)

您可以使用以下结构访问两个向量:

use std::mem;

#[derive(Debug)]
pub struct TwoArrays {
    pub a: Vec<i32>,
    pub b: Vec<i32>,
}

fn add_arrays(mut foo: TwoArrays) {
    let a = foo.a.clone();
    let mut b = foo.b.clone();

    for i in a.iter() {
        let mut index = 0;
        for _j in b.iter_mut() {
            let mut new_value = i.clone() + foo.b[index as usize].clone();
            mem::swap(&mut foo.b[index as usize], &mut new_value);
            index = index + 1;
        }
    }

    println!("Arrays A: {:?}", &foo.a);
    println!("Arrays A: {:?}", &foo.b);
}

fn main() {
    let a = vec![1i32, 2i32, 3i32];
    let b = vec![4i32, 5i32, 6i32];
    let two_arrays = TwoArrays { a, b };
    // let foo = Arc::new(Mutex::new(two_arrays));

    add_arrays(two_arrays);
}

Playground

  

为什么f会有不可变的借位?

因为您尝试使用iter()而不是iter_mut()进行迭代

  

为什么当我直接传递TwoArrays时没有发生这种情况?仅当我将其作为Arc<Mutex<TwoArrays>>

传递时才会发生

您可以将其作为裸结构传递,而无需使用示例代码使用Arc<Mutex<>>

如果您坚持使用Arc<Mutex<>>通过原子引用传递相同的对象,则可以将函数签名更改为以下内容:

fn add_arrays(mut foo: Arc<Mutex<TwoArrays>>)

您需要lock()并通过以下操作从Arc获取该引用:

let foo = foo.lock().unwrap();

Playground With Arc Usage