Rust:并发错误,程序在第一个线程之后挂起

问题描述 投票:0回答:1

我在下面为我的问题创建了简化版,我有一个Bag结构和Item结构。我想在item_action中的每个item上从Bag中生成10个执行item_list方法的线程,并在两个项目的属性都在bag的attributes中时打印一条语句。

use std::sync::{Mutex,Arc};
use std::thread;

#[derive(Clone, Debug)]
struct Bag{
    attributes: Arc<Mutex<Vec<usize>>>
}

impl Bag {
    fn new(n: usize) -> Self {
        let mut v = Vec::with_capacity(n);
        for _ in 0..n {
            v.push(0);
        }

        Bag{
            attributes:Arc::new(Mutex::new(v)),
        }
}

    fn item_action(&self, item_attr1: usize, item_attr2: usize) -> Result<(),()> {

        if self.attributes.lock().unwrap().contains(&item_attr1) ||
        self.attributes.lock().unwrap().contains(&item_attr2) {

            println!("Item attributes {} and {} are in Bag attribute list!", item_attr1, item_attr2);
            Ok(())
        } else {
            Err(())
        }
    }
}

#[derive(Clone, Debug)]
struct Item{
    item_attr1: usize,
    item_attr2: usize,
}

impl Item{
    pub fn new(item_attr1: usize, item_attr2: usize) -> Self {
        Item{
            item_attr1: item_attr1,
            item_attr2: item_attr2
        }
    }
}

fn main() { 
    let mut item_list: Vec<Item> = Vec::new();
    for i in 0..10 { 
        item_list.push(Item::new(i, (i+1)%10));
    }

    let bag: Bag= Bag::new(10); //create 10 attributes

    let mut handles = Vec::with_capacity(10);

    for x in 0..10 {
        let bag2 = bag.clone();
        let item_list2= item_list.clone();

        handles.push(
            thread::spawn(move || {
                bag2.item_action(item_list2[x].item_attr1, item_list2[x].item_attr2);
            })
        )
    }

    for h in handles {
        println!("Here");
        h.join().unwrap();
    }
}

运行时,我只有一行,程序只是在那儿停了下来而没有返回。

Item attributes 0 and 1 are in Bag attribute list!

我可以知道出了什么问题吗?请参阅Playground中的代码>

更新

根据@loganfsmyth的建议,该程序现在可以返回...,但仍然只打印上述一行。我希望它打印10,因为我的item_list有10个项目。不知道我的线程逻辑是否正确。

我在调用println!("Here");所有线程时都添加了join。而且我可以看到Here被打印了10次,但不是item_action的实际日志

我在下面为我的问题创建了简化版,我有一个Bag结构和Item结构。我想在item_list中的每个项目上产生10个从Bag执行item_action方法的线程,然后...

我相信这是因为Rust没有运行您的

if self.attributes.lock().unwrap().contains(&item_attr1) ||
    self.attributes.lock().unwrap().contains(&item_attr2) {

按您期望的顺序表达。目前,Rust中子表达式的求值顺序是不确定的。看来正在发生的事情实际上是您最终得到了

const condition = {
  let lock1 = self.attributes.lock().unwrap();
  let lock2 = self.attributes.lock().unwrap();
  lock1.contains(&item_attr1) || lock2.contains(&item_attr2)
};
if condition {

这导致您的代码陷入僵局。

您应该写:

let attributes = self.attributes.lock().unwrap();
if attributes.contains(&item_attr1) ||
   attributes.contains(&item_attr2) {

所以只有一把锁。

如果您使用RwLockRwLock而不是ReentrantMutex,您的代码也将照常工作,因为它们允许同一线程对数据具有多个不可变的引用。

multithreading concurrency rust
1个回答
0
投票

我相信这是因为Rust没有运行您的

© www.soinside.com 2019 - 2024. All rights reserved.