Merge changes from sftblw into master

sarojaba authored
revision 53abe55bbce96bf630d9e530230349d972ae2ad6
dining-philosophers
# 3.2. 식사하는 철학자들의 만찬 (Dining Philosophers) - 100%

우리의 두 번째 프로젝트를 위해, 고전적인 동시성 문제를 살펴봅시다. '식사하는 철학자들의 만찬'이라 불리는 문제인데요. 이 문제는 다익스트라_Dijkstra_에 의해 1965년 처음으로 고안되었지만, 우리는 1985년 토니 호어의 [이 논문][paper]에 실린 것이 가볍게 적용된 버전을 사용할 것입니다.

[paper]: http://www.usingcsp.com/cspbook.pdf


> 고대, 어떤 부유한 자선사업가가 다섯 명의 저명한 철학가를 모실 수 있도록 한 대학을 후원했습니다.
> 각각의 철학자들은 그들이 그들의 전문적인 사고에 몰입할 수 있는 방을 하나씩 얻었죠. 그리고 공동으로
> 사용하는 식당이 하나 있었는데, 그 식당에는 각 철학자들의 이름이 새겨진 다섯 의자로 둘러쌓인
> 원형 식탁이 있었습니다. 철학자들은 이 식닥을 둘러싸고 반시계 방향으로 앉았습니다. 각 철학자의
> 왼쪽에는 금으로 된 포크가 하나씩 놓여 있었고, 식탁의 중앙에는 계속해서 채워지는, 스파게티가
> 가득 담긴 쟁반이 놓여 있었죠. 대학에서는 철학자라는 이들은 어차피 대부분의 시간을 그저
> 생각하는데에 사용했습니다. 하지만, 배고픔을 느낄 때에는 중앙의 식당으로 와서, 자기 이름이
> 쓰인 의자에 앉은 뒤에, 그의 왼쪽에 놓인 그의 포크를 집어들고, 스파게티에 그걸 내리꽂았죠.
> 하지만 스파게티란게 워낙에 꼬여 있는 음식인지라, 스파게티를 입으로 옮기기 위해서는 포크가
> 하나 더 필요했어요. 따라서 그 철학자는 그의 오른쪽에 놓인 포크를 집어들어야만 했죠. 배를
> 채운 뒤, 그 철학자는 양 손에 든 포크를 내려놓고, 의자에서 일어나, 다시 생각을 이어가겠죠.
> 당연히 하나의 포크는 한 번에 한 명만 사용 가능합니다. 만약 다른 철학자가 현재 사용중인
> 포크를 필요로 한다면, 지금 그 포크를 사용중인 철학자가 식사를 끝낼 때까지 기다려야해요.

이 고전적인 문제는 동시성의 몇 가지 요소들을 보여줍니다. 사실 이 문제를 구현하는 것은 좀 까다로운데, 단순하게 생각하고 구현했다가는 데드락이 발생할 수 있습니다. 예를 들어, 이 문제를 해결하기 위한 아래와 같은 단순한 알고리즘을 생각해봅시다.

1. 철학자가 자신의 왼쪽에 놓인 포크를 집어든다.
2. 그 다음엔 자기 오른쪽에 놓인 포크를 집어든다.
3. 먹는다.
4. 포크를 반납한다.

이제, 다음과 같은 일련의 사건들을 상상해보세요:

1. 철학자 1이 알고리즘을 시작하고, 자기 왼쪽에 놓인 포크를 집어듭니다.
2. 철학자 2가 알고리즘을 시작하고, 자기 왼쪽에 놓인 포크를 집어듭니다.
3. 철학자 3이 알고리즘을 시작하고, 자기 왼쪽에 놓인 포크를 집어듭니다.
4. 철학자 4가 알고리즘을 시작하고, 자기 왼쪽에 놓인 포크를 집어듭니다.
5. 철학자 5가 알고리즘을 시작하고, 자기 왼쪽에 놓인 포크를 집어듭니다.
6. ...?
모든 포크는 사용중이지만, 아무도 먹을 수 없죠!

이 문제를 해결 할 수 있는 여러가지 방법이 있습니다. 이 튜토리얼 내에서 우리도 우리의 해결책을 찾아낼 거에요. 일단 지금 당장은, 문제 자체부터 모델링해보죠. 철학자들부터 시작합시다.

```rust
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`][struct]를 만들었습니다. 지금으로서는, 이름이 우리가 필요로 하는 전부죠. 이름을 나타내기 위해서 `&str`이 아니라 [`String`][string] 타입을 선택했습니다. 일반적으로, 실제 값에 대한 주소를 갖고 있는 참조를 사용하는 것보다는 그 자신이 값을 들고 있는 타입을 쓰는 게 수월합니다.

[struct]: structs.html
[string]: strings.html

계속 해 봅시다.

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

이 `impl` 블락을 통해 우리는 `Philosopher` 구조체 내에 여러가지를 정의할 수 있습니다. 이 경우, `new`라고 불리는, 연관된 함수를 정의했죠. 첫 라인은 다음과 같습니다.

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

여기서 우리는 `&str` 타입을 갖는 `name`이라는 인자 하나를 받죠. 이 인자는 다른 문자열에 대한 참조입니다. 그리고 `Philosopher` 구조체 인스턴스를 리턴합니다.

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

이 함수는 새로운 `Philosopher`를 생성하고, 그것의 `name`을 우리의 `name`인자로 설정합니다. 다만, 인자 그 자체가 아닌, 인자에 `.to_string()`을 호출한 것을 말이죠. 이 함수는 우리의 `&str`가 가리키고 있는 문자열의 복사본을 생성하고, 우리에게 새로 만들어진 `String`을 줍니다. `Philsopher`의 `name` 필드의 타입과 같죠.

왜 직접 `String`을 받지 않을까요? 호출의 용이성 때문입니다. 만약 우리가 `String`을 받지만, 호출자는 `&str`를 갖고 있다면, 호출자가 직접 `.to_string()`을 호출해야 할 것입니다. 이러한 유연성의 단점은 우리가 _항상_ 복사본을 만든다는 것입니다. 이것과 같이 조그마한 프로그램에 대해서는, 어차피 우리가 짧은 문자열만 사용할 것을 알기 때문에 그렇게 큰 문제는 아니지만요.

마지막으로 주목하셔야 할 것이 하나 있습니다. 우리는 `Philosopher`를 정의했지만, 그걸로 아무 일도 하지 않는 것처럼 보입니다. Rust는 '표현 기반' 언어입니다. 이는 Rust에서는 거의 모든 것이 어떤 값을 리턴하는 표현식임을 의미하죠. 이는 함수에도 마찬가지로 적용되는데, 함수의 마지막 표현식이 자동으로 리턴됩니다. 우리가 이 함수의 마지막 표현식에서 새로운 `Philosopher`를 생성했기 때문에, 이 함수는 그것을 리턴합니다.

이 함수의 이름인 `new()`는 Rust에게는 아무런 특별한 의미를 갖지 않지만, 구조체의 새로운 인스턴스를 생성하는 함수들에 관습적으로 사용됩니다. 왜인지 이야기하기 전에, `main()` 함수를 다시 살펴보죠.


```rust
# 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");
}
```

여기서, 우리는 다섯 명의 철학자들을 이용해 다섯 개의 변수 바인딩을 생성했습니다. 이 사람들은 제가 가장 좋아하는 다섯 명인데, 여러분은 여러분이 원하는 분으로 바꾸셔도 상관 없습니다. 만약 우리가 `new()` 함수를 정의하지 _않았다면_, 다음과 같이 작성해야 했겠죠.

```rust
# 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() };
}
```

훨씬 부산스럽죠? `new`를 사용하는 것은 다른 여러 장점들도 가지고 있지만, 이렇게 간단한 경우에조차, 코드를 작성하기가 훨씬 편리해집니다.

이제 기초적인 내용들을 알았으니, 이 문제에 도전해 볼 수 있는 여러가지 방법들이 존재합니다. 끝 부분부터 작성해 볼까요? 각각의 철학자들이 식사를 마칠 수 있는 방법을 마련해봅시다. 작은 발걸음부터 떼는 의미에서, 메소드 하나를 생성하고, 모든 철학자를 돌면서 그 메소드를 호출해봅시다.

```rust
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();
}
}
```

`main()` 함수를 먼저 살펴보죠. 다섯 철학자들을 위해 5개의 변수 바인딩을 각각 만드는 대신, 그들의 `Vec`를 만들어 봅시다. `Vec`는 '벡터'라고도 불리우는데, 성장 가능한 배열 타입이에요. 그 뒤에는 [`for` 반복문][for]을 이용해서 벡터 내를 순회하며 차례로 각각의 철학자들을 가리키는 참조를 얻어옵니다.

[for]: for-loops.html

반복문의 몸체에서, 우리는 위에서 정의한 `p.eat()`을 호출합니다.

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

Rust에서, 메소드는 명시적인 `self` 파라미터를 받습니다. 그게 `eat()`은 메소드이지만 `new`는 연관된 함수인 이유인데요. `new()`는 `self`를 갖지 않죠. 우리의 초기 버전 `eat()`에서 우리는 그냥 철학자의 이름을 출력한 뒤 그가 식사를 끝냈다고 언급합니다. 이 프로그램을 돌리면 다음과 같은 결과를 얻게 되겠죠.

```text
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.
```

어렵지 않죠? 모두가 식사를 마쳤군요! 하지만 우리는 실제 문제를 구현하지 않았으므로, 우리는 아직 갈 길이 많이 남았습니다.

다음으로, 우리는 철학자들이 식사를 마치기만 하는게 아니라, 실제로 식사를 하길 원합니다. 다음 버전은 이렇게 생겼어요.

```rust
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);

thread::sleep_ms(1000);

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

몇 가지 변화가 있었죠. 쪼개서 살펴봅시다.

```
rust, ignore
use std::thread;
```

`use`는 이름을 유효 범위 내로 끌어들입니다. 우리는 표준 라이브러리에 있는 `thread` 모듈을 사용하기 시작할거고, 따라서 그 모듈을 `use` 해야하죠.

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

thread::sleep_ms(1000);

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

이제 우리는 두 메세지를 출력하는데, 그 사이에 `sleep_ms()`가 있네요. 이 함수는 철학자가 식사를 하는데 걸리는 시간을 시뮬레이트합니다.

이 프로그램을 실행시키면, 각각의 철학자가 차례로 식사를 하는 것을 볼 수 있을 것입니다.

```text
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.
```

훌륭하군요! 점점 목표에 가까워지고 있습니다. 다만 문제가 하나 있는데, 우리는 지금 동시성을 고려하는 방식으로 작업하지 않고 있죠. 동시성은 이 문제의 핵심인데 말이에요!

철학자들이 동시적으로 식사하도록 만들기 위해, 작은 변화를 만들 필요가 있습니다.
다음 버전입니다.

```rust
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);

thread::sleep_ms(1000);

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| {
thread::spawn(move || {
p.eat();
})
}).collect();

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

우리가 한 일이라곤 `main()`내의 반복문을 약간 바꾸고, 두 번째 반복문을 추가한 것 뿐이에요! 첫 번째 변화는 다음과 같습니다.

```
rust,ignore
let handles: Vec<_> = philosophers.into_iter().map(|p| {
thread::spawn(move || {
p.eat();
})
}).collect();
```

위의 코드는 다섯 줄 밖에 안 되지만, 이 다섯 줄은 매우 밀도 있는 라인입니다.
하나씩 살펴보죠.

```
rust,ignore
let handles: Vec<_> =
```

여기서, `handles`라는 이름을 갖는 새로운 바인딩이 등장합니다. 이러한 이름을 준 이유는 우리가 새로운 쓰레드들을 생성할거고, 이 때 그 쓰레드들의 동작을 제어할 수 있는 핸들이 리턴될 것이기 때문이에요. 좀 더 나중에 이야기할 이유 때문에, 여기서는 명시적으로 타입을 기술해주어야 합니다. `_`는 타입 플레이스홀더입니다. 우리는 "`handles`는 무언가의 벡터인데, 그 무언가가 뭐인지는 Rust 네가 알아맞춰보렴" 이라고 말하고 있는거에요.

```
rust,ignore
philosophers.into_iter().map(|p| {
```

우리는 철학자의 리스트를 받은 뒤에 거기에다가 `into_iter()`를 호출합니다. 이를 통해 철학자 각각의 소유권을 갖는 반복자가 반환됩니다. 우리는 각각의 소유권을 쓰레드들에 전달하기 위해 이러한 일을 하는데요. 그 반복자에 `map`을 호출하는데, `map`은 인자로 클로저를 받고 각각의 원소들에 그 클로저를 차례로 호출합니다.

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

여기가 동시성이 일어나는 지점입니다. `thread::spawn` 함수는 인자로 클로저를 받고 새로운 스레드에서 그 클로저 구문을 실행합니다. 이 클로저는 전에 가지고 왔던 값들의 소유권을 받아오기 위해 `move`라는 특별한 명시가 필요합니다. 주로 `map` 함수의 `p` 값들을 말이죠.

스레드 내부에서 우리는 단지 `p`의 `eat()`을 호출하는 일이 전부입니다. 또한 `thread::spawn`함수는 표현식을 만들기 때문에, 끝에 지긋지긋한 `;`이 없는 것에 주목하세요. 이 구분이 중요한 이유는 올바른 반환 값을 넘겨줘야하기 때문입니다. 더 상세한 정보는, [Expressions vs. Statements][es]를 읽어보세요.

[es]: functions.html#expressions-vs.-statements

```rust,ignore
}).collect();
```

마지막으로, `map` 호출의 결과를 받아 그들을 모아야 합니다. `collect()`함수는 이들을 어떤 종류의 모음(collection)으로 만드는데, 이 때문에 우리가 리턴 타입을 명시해줘야 했던 것입니다: `Vec` 타입으로 원해요. 각 스레드들에서 처리를 했던 `thread::spawn` 호출의 반환 값들이 요소가 됩니다. 휴!

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

`main()`의 끝에는 `handles`에 대해 루프를 돌며 각각 그것들에 `join()`을 호출합니다. 이것은 스레드가 작업을 완료할때까지 실행을 기다리게 됩니다. 따라서 프로그램이 끝나기 전에 스레드가 작업을 완료한다는 것을 보증할 수 있습니다.

프로그램을 실행해보면, 철학자들이 음식을 마구 먹고 있습니다!
멀티스레딩을 한 것입니다!

```text
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.
```

그런데 포크는 어쨌을까요? 우리는 아직 구현하지 않았습니다.

새로 `struct`를 만듭시다:

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

struct Table {
forks: Vec>,
}
```
이 `Table`은 `Mutex`들의 벡터를 가지고 있습니다. 뮤텍스는 동시성을 제어하는 방법 중 하나입니다: 한번에 오직 한 스레드만이 내부에 접근할 수 있습니다. 우리의 포크를 만드는데 딱 필요한 성질입니다. 실제로 값을 쓰지는 않고 그저 들고 있기만 하면 되기 때문에, 빈 튜플인 `()`를 뮤텍스 안에 사용했습니다.

`Table`을 사용할 프로그램을 수정해봅시다:

```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();
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>,
}

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

많이 바뀌었군요! 하지만 많은 요소가 반복되어서, 프로그램을 이해할 수 있습니다.
자세하게 들어가보죠:

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

`std::sync` 패키지에 있는 `Arc`를 쓰려고 합니다. 실제 사용할 때 자세히 얘기하죠.

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

`Philosopher`에 2개의 필드를 추가했습니다. 각 철학자들은 2개의 포크를 가집니다: 하나는 왼쪽, 하나는 오른쪽. `usize`타입은 벡터 인덱스(e.g. Vec[index]) 타입입니다. 이 두 값은 `Table`이 가진 `forks`의 인덱스가 될 것입니다.

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

`new()`에서 `left`와 `right`값을 설정해줄 필요가 있습니다.

```rust,ignore
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);

thread::sleep_ms(1000);

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

`table`을 인자로 받는 것과 두 줄이 추가되었습니다. `Table`의 forks 리스트에서 `self.left`와 `self.right`로 특정 인덱스들에 접근할 수 있습니다. 그렇게 함으로써 그 인덱스들의 `Mutex`에 접근할 수 있고 `lock()`을 호출할 수 있습니다. 만약 해당 뮤텍스가 현재 누군가에게 접근되었다면, 다시 사용가능할때까지 잠급니다.

`lock()`호출은 종종 실패하는데, 그 경우 충돌이 일어납니다. 이 오류는 뮤텍스가 [‘poisoned’][poison]일때 일어날 수 있습니다. [‘poisoned’][poison]는 잠겨 있는 도중에 스레드가 패닉(panic)할 때 일어납니다. 이러한 일은 일어나선 안되므로, `unwrap()`을 사용해줍니다.

[poison]: ../std/sync/struct.Mutex.html#poisoning

그 두줄에 이상한 것이 또 있습니다: 결과에 `_left`와 `_right`라 이름붙였습니다. 이 밑줄은 뭔가요? 음, 우리는 잠긴 값을 _사용할(using)_ 예정이 없습니다. 우리는 단지 값을 얻어오면 됩니다. 그래서, 러스트는 이 값들이 사용되지 않았다고 경고할 것입니다. 밑줄을 사용하면, 러스트에게 '이건 일부러 그런거야'라고 알려주고, 경고를 내뱉지 않을 겁니다.

그런데 잠금 해제는 어떻게 하나요? 호, `_left`와 `_right`가 스코프 밖으로 나가면 자동적으로 이루어집니다.

```rust,ignore
let table = Arc::new(Table { forks: vec![
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
]});
```
다음으로 `main()`에서, 새로운 `Table`을 만들고 `Arc`로 감쌉니다. 'arc'는 '원자적 참조 카운트(atomic reference count)를 나타냅니다. 다수의 스레드에서 우리의 `Table`을 나눌 필요가 있습니다. 우리가 그것을 나누면 참조 카운트가 올라가고, 각 스레드가 끝나면 다시 내려갑니다.


```rust,ignore
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),
];
```
`Philosopher`를 생성할 때, 생성자에게 `left`와 `right` 값을 넘겨주어야 합니다. 한 가지 더 자세하고 _매우_ 중요한 것이 있습니다. 패턴을 잘 살펴보면, 끝에 이르기전까진 일정합니다. 그런데 Michel Foucault가 `0, 4`로 되어있습니다. `4, 0`이 아니라요. 사실 이것이 데드락을 막아줍니다: 우리의 철학자들 중 한 명은 왼손잡이라는 것 말입니다! 저는 이 방법이 문제를 해결하는 가장 간단한 해법 중 하나라고 생각합니다.

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

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

마지막으로, `map()`/`collect()` 루프를 사용하는 대신, `table.clone()`을 호출했습니다. `clone()`함수는 `Arc`에 있는 메소드로써 참조 카운트를 올리고, 그것이 스코프 밖으로 나가면 카운트를 줄입니다. 스레드들을 넘어서 `table`에 참조가 얼마나 되었는지 알기 위해서 필요합니다. 만약 이러한 카운트가 없다면, 그것을 어떻게 해제(deallocate)해야할지 알 수 없을 겁니다.

아마 당신은 기존의 이름을 갱신하는 `table`의 새로운 바인딩 방식에 대해 눈치채셨을지도 모르겠습니다. 딱히 또 다른 새로운 이름을 만들 필요가 없을 때 사용합니다.

이것들로, 프로그램이 완성되었습니다! 오직 두 철학자만이 한번에 음식을 먹을 수 있고, 다음과 같은 결과를 볼 수 있습니다:

```text
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.
```

축하합니다! 당신은 러스트를 통해 고전적인 동시성 문제를 해결했습니다.