我正试图跟随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 {
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();
}
}
Run Code Online (Sandbox Code Playgroud)
运行此命令会产生以下输出:
Michel Foucault is eating.
Michel Foucault is done eating.
Emma Goldman is eating.
Emma Goldman is done eating.
Karl Marx is eating.
Karl Marx is done eating.
Gilles Deleuze is eating.
Gilles Deleuze is done eating.
Judith Butler is eating.
Judith Butler is done eating.
Run Code Online (Sandbox Code Playgroud)
根据文件,哲学家应该能够同时吃饭.期望的结果是这样的:
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.
Run Code Online (Sandbox Code Playgroud)
不幸的是,无论代码执行的频率如何,都不会发生这种情况.
我目前正在rustc 1.5.0 (3d7cd77e4 2015-12-04)Windows上使用,但问题也发生在Rust操场上.随意尝试一下.
由于拣货叉之间的睡眠,问题的实施和建议的输出不匹配.
我不确定为什么Michel Foucault总是首先开始(可能是线程调度的方式),但其余部分很容易解释.
由于抓住主手叉和副手叉之间的暂停(*),有两个阶段:
第1阶段后:
现在,请注意,只有Fork 4可供抓取!
我们在第2阶段有两个案例:
a)朱迪思抓住了叉子0 b)米歇尔抓住了叉子0
从(a)开始:
在(a)的情况下,只有一个哲学家可以在任何给定的时间吃东西.
注意:我强迫这个案子暂停了Michel 150ms,然后让他抓住他的第一个叉子.
案例(b)更加复杂,因为我们再次参加比赛,这次是艾玛和米歇尔之间的比赛,我们是绅士,所以艾玛会先走,米歇尔抓住福克斯4的案子现在被命名为(c) :
我们观察到非常有限的并发性:Emma首先命中,只有当她完成时我们才有两个并行流,一个是Michel,一个是Karl> Gilles> Judith.
注意:我强迫这个案子暂停了Michel 150ms,然后让他抓住他的第二个叉子.
最后,我们有案例(c):
而且在这里,根本没有并发性.
(*)这实际上并没有保证,但150ms是计算机方面的长时间,除非机器非常负载,它才会发生.
虽然本书提出的解决方案确实有效(在任何情况下都没有死锁),但它并没有表现出太多的并发性,因此它更像是Rust的展示而不是并发展......但是,它是Rust书而不是并发的!
我不明白为什么Michel的主题是先在围栏上系统安排的; 但是可以通过让他专门睡觉来轻松应对.
| 归档时间: |
|
| 查看次数: |
944 次 |
| 最近记录: |