Concurrency Rust文档中的用餐哲学家不同时吃饭

Concurrency Rust文档中的用餐哲学家不同时吃饭,concurrency,rust,Concurrency,Rust,我正试图按照锈迹文件中的说明进行操作。链接中的最终代码: use std::thread; use std::sync::{Mutex, Arc}; struct Philosopher { name: String, left: usize, right: usize, } impl Philosopher { fn new(name: &str, left: usize, right: usize) -> Philosopher {

我正试图按照锈迹文件中的说明进行操作。链接中的最终代码:

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

struct Philosopher {
    name: String,
    left: usize,
    right: usize,
}

impl Philosopher {
    fn new(name: &str, left: usize, right: usize) -> Philosopher {
        Philosopher {
            name: name.to_string(),
            left: left,
            right: right,
        }
    }

    fn eat(&self, table: &Table) {
        let _left = table.forks[self.left].lock().unwrap();
        thread::sleep_ms(150);
        let _right = table.forks[self.right].lock().unwrap();

        println!("{} is eating.", self.name);

        thread::sleep_ms(1000);

        println!("{} is done eating.", self.name);
    }
}

struct Table {
    forks: Vec<Mutex<()>>,
}

fn main() {
    let table = Arc::new(Table { forks: vec![
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
    ]});

    let philosophers = vec![
        Philosopher::new("Judith Butler", 0, 1),
        Philosopher::new("Gilles Deleuze", 1, 2),
        Philosopher::new("Karl Marx", 2, 3),
        Philosopher::new("Emma Goldman", 3, 4),
        Philosopher::new("Michel Foucault", 0, 4),
    ];

    let handles: Vec<_> = philosophers.into_iter().map(|p| {
        let table = table.clone();

        thread::spawn(move || {
            p.eat(&table);
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}
根据文献记载,哲学家应该能够同时吃饭。预期结果如下所示:

Gilles Deleuze is eating.
Emma Goldman is eating.
Emma Goldman is done eating.
Gilles Deleuze is done eating.
Judith Butler is eating.
Karl Marx is eating.
Judith Butler is done eating.
Michel Foucault is eating.
Karl Marx is done eating.
Michel Foucault is done eating.
不幸的是,无论代码执行的频率有多高,这种情况都不会发生


我目前正在Windows上使用
rustc 1.5.0(3d7cd77e4 2015-12-04)
,但问题也发生在生锈的操场上。请随意。

由于拣货叉之间的休眠,问题的实现与建议的输出不匹配

我不确定为什么米歇尔·福柯总是先开始(可能是线程调度的工作方式),但其余的很容易解释

由于抓取主叉和非手叉之间的停顿(*),分为两个阶段:

  • 第1阶段:抓住你的主手叉
  • 第二阶段:拿起你的非手动叉子
第一阶段之后:

  • 叉子0在米歇尔·福柯或朱迪思·巴特勒手中
  • 叉子1在Gilles Deleuze手中
  • 叉子2在卡尔·马克思手中
  • Fork 3在Emma Goldman手中
现在,请注意,只有Fork 4可用于抓取

我们在第二阶段有两个案例:

a) 朱迪思抓起叉子 b) 米歇尔抓起叉子

从(a)开始:

  • 除了艾玛,所有的哲学家都被封锁了,她抓住了叉子
  • 爱玛完成后,她松开叉子3,卡尔立即抓住叉子
  • 卡尔做完后
  • 最后,朱迪思完成了,她松开叉子,米歇尔吃了
在案例(a)中,任何时候只有一个哲学家可以吃饭

注意:我强迫Michel暂停150毫秒,然后让他拿第一把叉子

案件(b)更为复杂,因为我们又一次有了一场比赛,这次是艾玛和米歇尔争夺福克4号。我们都是绅士,所以艾玛会先说,米歇尔抓叉4的案例现在命名为(c):

  • 艾玛抓起叉子4,其他所有的哲学家都被封锁了
  • 当爱玛完成后,她松开了叉子3和4,米歇尔和卡尔都跳了上去
  • 当Michel完成后,他释放了叉子0和4,Judith立即抓住它。。。开始等待;现在没人关心Fork 4了
  • 卡尔完成后,他松开叉子2,吉尔立即抓住叉子
  • 当Gilles完成后,他松开叉子1,Judith立即抓住叉子
  • 朱迪思吃完后,5个人都吃了
我们在这里观察到非常有限的并发性:Emma先点击,只有当她完成时,我们才有两条平行流,一条是Michel,另一条是Karl>Gilles>Judith

注:我强迫米歇尔暂停150毫秒,然后让他拿第二把叉子

最后,我们有案例(c):

  • 米歇尔抓起叉子4,所有其他哲学家现在都被封锁了
  • 当Michel完成后,他释放Fork 4和0,分别被Emma和Judith抓住;朱迪思仍然被堵住了(先是睡觉,然后等叉子1),但艾玛开始吃东西
  • 当艾玛结束时
这里再次强调,根本没有并发性

(*)这实际上并不能保证,但150ms是一个很长的计算机时间,除非机器负载很大,否则它就会发生


虽然这本书提出的解决方案确实有效(无论在什么情况下都不会出现死锁),但它并没有表现出太多的并发性,因此它更多的是一种生锈的表现,而不是并发性的表现。。。但是,这是铁锈书,而不是并发书


我不明白为什么Michel的线程被系统地排在playpen的第一位;但这很容易通过让他具体睡觉来应对。

这是这个例子中的一个半常见问题。程序员倾向于认为线程是“随机的”,因为线程通常有不同的开始时间和运行长度。线程的大多数用法也不会在线程的整个生命周期中锁定共享资源。请记住,线程是确定性的,因为它们是由算法调度的

在本例中,主线程创建了一大堆线程,并将它们添加到操作系统管理的队列中。最终,主线程被调度程序阻塞或中断。调度程序查看线程队列并询问“第一个”线程是否可以运行。如果它是可运行的,那么它将运行一个时间片或直到它被阻塞

“第一个”线程由操作系统决定。例如,Linux有多个可调整的调度程序,允许您确定运行哪些线程的优先级。调度程序还可以选择提前或推迟中断线程

如果在线程的最开始添加打印,可以看到线程的开始顺序不同。下面是一个表,根据100次运行,哪个线程首先启动:

|职位|艾玛·戈德曼|吉尔·德勒兹|朱迪思·巴特勒|卡尔·马克思|米歇尔·福柯|
|----------+--------------+----------------+---------------+-----------+-----------------|
|        1 |            4 |              9 |            81 |         5 |               1 |
|        2 |            5 |             66 |             9 |        17 |               3 |
|        3 |           19 |             14 |             5 |        49 |              13 |
|        4 |           46 |              9 |             3 |        20 |              22 |
|        5 |           26 |              2 |             2 |         9 |              61 |
如果我正确地进行了统计,最常见的开始顺序是:

  • 朱迪思·巴特勒
  • 吉勒斯·德勒兹
  • 卡尔·马克思
  • 艾玛·戈德曼
  • 米歇尔·福柯
  • 请注意,这与代码中定义的哲学家序列相匹配

    还要注意的是,算法本身强加了一个顺序。除了一个哲学家之外,所有人都拿起了叉子
    Gilles Deleuze is eating.
    Emma Goldman is eating.
    Emma Goldman is done eating.
    Gilles Deleuze is done eating.
    Judith Butler is eating.
    Karl Marx is eating.
    Judith Butler is done eating.
    Michel Foucault is eating.
    Karl Marx is done eating.
    Michel Foucault is done eating.