# 哲学家就餐问题

dining-philosophers.md
commit c618c5f36a3260351a09f4b4dc51b2e5d1359fbc

1. 一个哲学家拿起左手边的叉子
2. 他接着拿起右手边的叉子
3. 他吃
4. 他返回叉子

1. 哲学家 1 开始算法，拿起他左手边的叉子
2. 哲学家 2 开始算法，拿起他左手边的叉子
3. 哲学家 3 开始算法，拿起他左手边的叉子
4. 哲学家 4 开始算法，拿起他左手边的叉子
5. 哲学家 5 开始算法，拿起他左手边的叉子
6. 。。。？所有的叉子都被拿走了，不过没人在吃（意大利面）！

$cd ~/projects$ cargo new dining_philosophers --bin
\$ cd dining_philosophers

struct Philosopher {
name: String,
}

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

fn main() {
let p1 = Philosopher::new("Judith Butler");     // 译者注：朱迪斯·巴特勒
let p2 = Philosopher::new("Gilles Deleuze");    // 译者注：吉尔·德勒兹
let p3 = Philosopher::new("Karl Marx");         // 译者注：卡尔·马克思
let p4 = Philosopher::new("Emma Goldman");      // 译者注：爱玛·戈德曼
let p5 = Philosopher::new("Michel Foucault");   // 译者注：米歇尔·福柯
}

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

impl块让我们在Philosopher上定义方法。在这个例子中，我们定义了一个叫做new的“关联函数”。第一行看起来像这样：

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

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

# struct Philosopher {
#     name: String,
# }
#
# impl Philosopher {
#     fn new(name: &str) -> Philosopher {
#         Philosopher {
#             name: name.to_string(),
#         }
#     }
# }
#
fn main() {
let p1 = Philosopher::new("Judith Butler");
let p2 = Philosopher::new("Gilles Deleuze");
let p3 = Philosopher::new("Karl Marx");
let p4 = Philosopher::new("Emma Goldman");
let p5 = Philosopher::new("Michel Foucault");
}

# struct Philosopher {
#     name: String,
# }
fn main() {
let p1 = Philosopher { name: "Judith Butler".to_string() };
let p2 = Philosopher { name: "Gilles Deleuze".to_string() };
let p3 = Philosopher { name: "Karl Marx".to_string() };
let p4 = Philosopher { name: "Emma Goldman".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("Judith Butler"),
Philosopher::new("Gilles Deleuze"),
Philosopher::new("Karl Marx"),
Philosopher::new("Emma Goldman"),
Philosopher::new("Michel Foucault"),
];

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

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

Judith Butler is done eating.
Gilles Deleuze is done eating.
Karl Marx is done eating.
Emma Goldman is done eating.
Michel Foucault is done eating.

use std::thread;
use std::time::Duration;

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("Judith Butler"),
Philosopher::new("Gilles Deleuze"),
Philosopher::new("Karl Marx"),
Philosopher::new("Emma Goldman"),
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);
}

Judith Butler is eating.
Judith Butler is done eating.
Gilles Deleuze is eating.
Gilles Deleuze is done eating.
Karl Marx is eating.
Karl Marx is done eating.
Emma Goldman is eating.
Emma Goldman is done eating.
Michel Foucault is eating.
Michel Foucault is done eating.

use std::thread;
use std::time::Duration;

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("Judith Butler"),
Philosopher::new("Gilles Deleuze"),
Philosopher::new("Karl Marx"),
Philosopher::new("Emma Goldman"),
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()的结尾，我们遍历这些句柄并在其上调用join()，它会阻塞执行直到线程完成执行。这保证了在程序结束之前这些线程都完成了它们的工作。

Judith Butler is eating.
Gilles Deleuze is eating.
Karl Marx is eating.
Emma Goldman is eating.
Michel Foucault is eating.
Judith Butler is done eating.
Gilles Deleuze is done eating.
Karl Marx is done eating.
Emma Goldman is done eating.
Michel Foucault is done eating.

use std::sync::Mutex;

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

use std::thread;
use std::time::Duration;
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("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();

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()可能会失败，而且如果它失败了，我们想要程序崩溃。在这个例子中，互斥锁可能发生的错误是“被污染了（poisoned）”，它发生于当线程在持有锁的同时线程恐慌了。因为这不应该发生，所以我们仅仅是使用unwrap()

    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();

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

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.