# 哲学家就餐问题

2018-08-12 22:03 更新

## 哲学家就餐问题

1. 一个哲学家拿起了自己左边的叉子。
2. 然后他又拿起了他右边的叉子。
3. 吃意大利面。
4. 放下叉子。

1. 哲学家 1 开始此算法，拿起他左边的叉子。
2. 哲学家 2 开始此算法，拿起他左边的叉子。
3. 哲学家 3 开始此算法，拿起他左边的叉子。
4. 哲学家 4 开始此算法，拿起他左边的叉子。
5. 哲学家 5 开始此算法，拿起他左边的叉子。
6. …？所有的餐叉都被拿起来了，没人能吃面了!

``````    struct Philosopher {
name: String,
}

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

fn main() {
let p1 = Philosopher::new("Baruch Spinoza");
let p2 = Philosopher::new("Gilles Deleuze");
let p3 = Philosopher::new("Karl Marx");
let p4 = Philosopher::new("Friedrich Nietzsche");
let p5 = Philosopher::new("Michel Foucault");
}``````

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

``    fn new(name: &str) -> Philosopher {``

``````    Philosopher {
name: name.to_string(),
}``````

``````    fn main() {
let p1 = Philosopher::new("Baruch Spinoza");
let p2 = Philosopher::new("Gilles Deleuze");
let p3 = Philosopher::new("Karl Marx");
let p4 = Philosopher::new("Friedrich Nietzsche");
let p5 = Philosopher::new("Michel Foucault");
}``````

``````    fn main() {
let p1 = Philosopher { name: "Baruch Spinoza".to_string() };
let p2 = Philosopher { name: "Gilles Deleuze".to_string() };
let p3 = Philosopher { name: "Karl Marx".to_string() };
let p4 = Philosopher { name: "Friedrich Nietzche".to_string() };
let p5 = Philosopher { name: "Michel Foucault".to_string() };
}``````

``````    struct Philosopher {
name: String,
}

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

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

fn main() {
let philosophers = vec![
Philosopher::new("Baruch Spinoza"),
Philosopher::new("Gilles Deleuze"),
Philosopher::new("Karl Marx"),
Philosopher::new("Friedrich Nietzsche"),
Philosopher::new("Michel Foucault"),
];

for p in &philosophers {
p.eat();
}
}``````

``````    fn eat(&self) {
println!("{} is done eating.", self.name);
}``````

``````    Baruch Spinoza is done eating.
Gilles Deleuze is done eating.
Karl Marx is done eating.
Friedrich Nietzsche is done eating.
Michel Foucault is done eating.``````

``````    use std::thread;

struct Philosopher {
name: String,
}

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

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

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

fn main() {
let philosophers = vec![
Philosopher::new("Baruch Spinoza"),
Philosopher::new("Gilles Deleuze"),
Philosopher::new("Karl Marx"),
Philosopher::new("Friedrich Nietzsche"),
Philosopher::new("Michel Foucault"),
];

for p in &philosophers {
p.eat();
}
}``````

``    use std::thread;``

use 可以使后面的库加载在作用域内。我们稍后会使用标准库中的 thread 模块，所以我们需要 use 它。

``````    fn eat(&self) {
println!("{} is eating.", self.name);

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

``````    Baruch Spinoza is eating.
Baruch Spinoza is done eating.
Gilles Deleuze is eating.
Gilles Deleuze is done eating.
Karl Marx is eating.
Karl Marx is done eating.
Friedrich Nietzsche is eating.
Friedrich Nietzsche is done eating.
Michel Foucault is eating.
Michel Foucault is done eating.``````

``````    use std::thread;

struct Philosopher {
name: String,
}

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

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

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

fn main() {
let philosophers = vec![
Philosopher::new("Baruch Spinoza"),
Philosopher::new("Gilles Deleuze"),
Philosopher::new("Karl Marx"),
Philosopher::new("Friedrich Nietzsche"),
Philosopher::new("Michel Foucault"),
];

let handles: Vec<_> = philosophers.into_iter().map(|p| {
p.eat();
})
}).collect();

for h in handles {
h.join().unwrap();
}
}``````

``````    let handles: Vec<_> = philosophers.into_iter().map(|p| {
p.eat();
})
}).collect();``````

``    let handles: Vec<_> =``

``    philosophers.into_iter().map(|p| {``

``````    thread::spawn(move || {
p.eat();
})``````

``    }).collect();``

``````    for h in handles {
h.join().unwrap();
}``````

main() 函数的结尾部分，我们对 handles 进行循环处理，对其调用 join()，这可以阻塞其它线程的执行，直到本线程执行完成。这确保了线程在程序将其退出前会完成它们的工作。

``````    Gilles Deleuze is eating.
Gilles Deleuze is done eating.
Friedrich Nietzsche is eating.
Friedrich Nietzsche is done eating.
Michel Foucault is eating.
Baruch Spinoza is eating.
Baruch Spinoza is done eating.
Karl Marx is eating.
Karl Marx is done eating.
Michel Foucault is done eating.``````

``````    use std::sync::Mutex;

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

``````    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();
let _right = table.forks[self.right].lock().unwrap();

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

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("Baruch Spinoza", 0, 1),
Philosopher::new("Gilles Deleuze", 1, 2),
Philosopher::new("Karl Marx", 2, 3),
Philosopher::new("Friedrich Nietzsche", 3, 4),
Philosopher::new("Michel Foucault", 0, 4),
];

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

p.eat(&table);
})
}).collect();

for h in handles {
h.join().unwrap();
}
}``````

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

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

``````    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();
let _right = table.forks[self.right].lock().unwrap();

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

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

lock() 的调用可能会失败，如果是这样，程序会崩溃。在这种情况下，错误的发生可能是因为互斥元“中毒”了，这是由于当锁已经被持有时会引起线程应急。因为这样的错误不该发生，所以我们使用 unwrap() 来解决它。

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

``````    let philosophers = vec![
Philosopher::new("Baruch Spinoza", 0, 1),
Philosopher::new("Gilles Deleuze", 1, 2),
Philosopher::new("Karl Marx", 2, 3),
Philosopher::new("Friedrich Nietzsche", 3, 4),
Philosopher::new("Michel Foucault", 0, 4),
];``````

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

p.eat(&table);
})
}).collect();``````

``````    Gilles Deleuze is eating.
Friedrich Nietzsche is eating.
Friedrich Nietzsche is done eating.
Gilles Deleuze is done eating.
Baruch Spinoza is eating.
Karl Marx is eating.
Baruch Spinoza is done eating.
Michel Foucault is eating.
Karl Marx is done eating.
Michel Foucault is done eating.``````

App下载