diff --git a/1.6/ja/book/dining-philosophers.md b/1.6/ja/book/dining-philosophers.md index 95df8b0c..24fcaae6 100644 --- a/1.6/ja/book/dining-philosophers.md +++ b/1.6/ja/book/dining-philosophers.md @@ -6,7 +6,7 @@ 私たちの2番目のプロジェクトとして、古典的な並行処理問題を考えていきましょう。「食事する哲学者(the dining philosophers)」とよばれる問題です。 -オリジナルは1965年にダイクストラ(Dijkstra)により考案されましたが、ここではトニー・ホーア(Tony Hoare)による1985年の[この論文][paper]を少しばかり脚色したバージョンを用います。 +オリジナルは1965年にダイクストラ(Dijkstra)により考案されましたが、ここではトニー・ホーア(Tony Hoare)による1985年の [この論文][paper] を少しばかり脚色したバージョンを用います。 [paper]: http://www.usingcsp.com/cspbook.pdf @@ -67,13 +67,13 @@ 3. 3番目の哲学者は、アルゴリズムに従って左側のフォークを取上げます。 4. 4番目の哲学者は、アルゴリズムに従って左側のフォークを取上げます。 5. 5番目の哲学者は、アルゴリズムに従って左側のフォークを取上げます。 -6. ...?全てのフォークが取られたのに、誰も食事できません! +6. ...?全てのフォークが取られたのに、誰も食事できません! この問題を解決する方法はいくつかあります。チュートリアルでは独自の解法をとります。 -さっそく、`cargo`を使って新規プロジェクトを作り始めましょう: +さっそく、 `cargo` を使って新規プロジェクトを作り始めましょう: ```bash $ cd ~/projects @@ -83,7 +83,7 @@ $ cd dining_philosophers -それでは、問題をモデル化するところから始めましょう。`src/main.rs`にて、哲学者から手を付けていきます: +それでは、問題をモデル化するところから始めましょう。 `src/main.rs` にて、哲学者から手を付けていきます: ```rust struct Philosopher { @@ -114,8 +114,8 @@ fn main() { -ここでは、哲学者を表す[`struct`(構造体)][struct]を作ります。まずは名前だけで十分でしょう。 -名前には`&str`型ではなく[`String`][string]型を選びました。一般的に、データを所有する型を用いた方が、 +ここでは、哲学者を表す [`struct` (構造体) ][struct] を作ります。まずは名前だけで十分でしょう。 +名前には `&str` 型ではなく [`String`][string] 型を選びました。一般的に、データを所有する型を用いた方が、 データを参照する型の利用よりも簡単になります。 [struct]: structs.html @@ -139,7 +139,7 @@ impl Philosopher { -この`impl`ブロックは`Philosopher`構造体に関する定義を与えます。ここでは、`new`という「関連関数」を定義します。 +この `impl` ブロックは `Philosopher` 構造体に関する定義を与えます。ここでは、 `new` という「関連関数(associated function)」を定義します。 最初の行は次の通りです: ```rust @@ -157,7 +157,7 @@ fn new(name: &str) -> Philosopher { -関数は`&str`型の引数1つ、`name`をとります。これは他の文字列への参照です。そして`Philosopher`構造体のインスタンスを返します。 +関数は `&str` 型の引数1つ、 `name` をとります。これは他の文字列への参照です。そして `Philosopher` 構造体のインスタンスを返します。 ```rust # struct Philosopher { @@ -176,17 +176,17 @@ Philosopher { -関数は新しい`Philosopher`インスタンスを作成し、その`name`フィールドに引数`name`を設定します。 -ここでは引数を直接設定するのではなく、`.to_string()`を呼び出しています。これにより`&str`が指す文字列のコピーが作られ、 -`Philosopher`の`name`フィールド型に合わせた新しい`String`が得られます。 +関数は新しい `Philosopher` インスタンスを作成し、その `name` フィールドに引数 `name` を設定します。 +ここでは引数を直接設定するのではなく、 `.to_string()` を呼び出しています。これにより `&str` が指す文字列のコピーが作られ、 +`Philosopher` の `name` フィールド型に合わせた新しい `String` が得られます。 -なぜ引数に直接`String`を受付けないのかって?いい質問です。仮に`String`をとるとしたら、呼出し元は`&str`値をもっていますから、 -呼出元でメソッドを呼ぶ必要がでしまいます。この利便性の代償として、_常に_コピーが作られてしまいます。 +なぜ引数に直接 `String` を受付けないのかって?いい質問です。仮に `String` をとるとしたら、呼出し元は `&str` 値をもっていますから、 +呼出元でメソッドを呼ぶ必要がでしまいます。この利便性の代償として、 _常に_ コピーが作られてしまいます。 今回のプログラムでは、短い文字列しか与えないことが分かっているため、これは大して重要な問題ではありません。 @@ -195,15 +195,15 @@ Philosopher { -最後の注意点として: ここは`Philosopher`を定義しただけで、何もしていないように見えます。Rust言語は「式ベース」なので、 +最後の注意点として: ここは `Philosopher` を定義しただけで、何もしていないように見えます。Rust言語は「式ベース(expression based)」なので、 Rustではほとんどが値を返す式となります。関数についても同じことが言え―最後の式が自動的に戻り値となります。 -ここでは関数内の最後の式で新しい`Philosopher`を生成し、それを戻り値としているのです。 +ここでは関数内の最後の式で新しい `Philosopher` を生成し、それを戻り値としているのです。 -この`new()`という名前、Rustにとって特別な意味を持ちませんが、構造体の新しいインスタンスを生成する関数としてよく用いられます。 -その理由について話す前に、再び`main()`を見ていきましょう: +この `new()` という名前、Rustにとって特別な意味を持ちませんが、構造体の新しいインスタンスを生成する関数としてよく用いられます。 +その理由について話す前に、再び `main()` を見ていきましょう: ```rust # struct Philosopher { @@ -230,7 +230,7 @@ fn main() { -ここでは、5つの新しい哲学者に対して5つの変数束縛を作ります。仮に`new`関数を定義_しない_なら、次ように書く必要があります: +ここでは、5つの新しい哲学者に対して5つの変数束縛を作ります。仮に `new` 関数を定義 _しない_ なら、次ように書く必要があります: ```rust # struct Philosopher { @@ -247,7 +247,7 @@ fn main() { -これでは面倒ですよね。`new`の利用には他の利点もありますが、今回のような単純なケースでも、 +これでは面倒ですよね。 `new` の利用には他の利点もありますが、今回のような単純なケースでも、 利用側コードをシンプルにできるのです。 @@ -295,14 +295,14 @@ fn main() { -最初は`main()`から見ていきます。哲学者たちに5つの変数束縛を個別に行うのではなく、代わりに`Vec`を用いました。 -`Vec`は「ベクトル」とも呼ばれる、可変長の配列型です。ベクトルの走査には[`for`][for]ループを使っているため、 +最初は `main()` から見ていきます。哲学者たちに5つの変数束縛を個別に行うのではなく、代わりに `Vec` を用いました。 +`Vec` は「ベクタ(vector)」とも呼ばれる、可変長の配列型です。ベクタの走査には [`for`][for] ループを使っているため、 それぞれの哲学者への参照が順番に得られれます。 [for]: loops.html#for -ループ本体の中では、上記で定義した`p.eat()`を呼び出します: +ループ本体の中では、上記で定義した `p.eat()` を呼び出します: ```rust,ignore fn eat(&self) { @@ -315,8 +315,8 @@ fn eat(&self) { -Rustでは、メソッドは明示的な`self`パラメータを取ります。なので`eat()`はメソッドとなり、 -`new()`は`self`を取らないため関連関数となります。最初の`eat()`バージョンでは、哲学者の名前と、 +Rustでは、メソッドは明示的な `self` パラメータを取ります。なので `eat()` はメソッドとなり、 +`new()` は `self` を取らないため関連関数となります。最初の `eat()` バージョンでは、哲学者の名前と、 食事が終わったことを表示するだけです。このプログラムを実行すると次の出力がえられるはずです: ```text @@ -329,7 +329,7 @@ Michel Foucault is done eating. -これだけなら簡単ですね、出来ました!私たちはまだ真の問題を実装していませんから、実際のところは出来ていませんけど! +これだけなら簡単ですね、出来ました!私たちはまだ真の問題を実装していませんから、実際のところは出来ていませんけど! @@ -383,7 +383,7 @@ use std::thread; -`use`は名前をスコープに持ち込みます。標準ライブラリから`thread`モジュールを使いたいので、`use`が必要になります。 +`use` は名前をスコープに持ち込みます。標準ライブラリから `thread` モジュールを使いたいので、 `use` が必要になります。 ```rust,ignore fn eat(&self) { @@ -397,7 +397,7 @@ use std::thread; -今回は間に`sleep`を挟んで、2つのメッセージを出力します。これで哲学者が食事をする時間をシミュレートしましょう。 +今回は間に `sleep` を挟んで、2つのメッセージを出力します。これで哲学者が食事をする時間をシミュレートしましょう。 このプログラムを実行すると、哲学者たちが順番に食事する様子がわかります: @@ -417,7 +417,7 @@ Michel Foucault is done eating. -素晴らしい!ここまで来ました。残る問題はたった1つ: この問題の核心である並行性に関して、実際には手を付けていませんね! +素晴らしい!ここまで来ました。残る問題はたった1つ: この問題の核心である並行性に関して、実際には手を付けていませんね! @@ -470,7 +470,7 @@ fn main() { -`main()`内のループ変更と、1ヵ所の追加で全部です!まずは前半の変更から: +`main()` 内のループ変更と、1ヵ所の追加で全部です!まずは前半の変更から: ```rust,ignore let handles: Vec<_> = philosophers.into_iter().map(|p| { @@ -493,10 +493,10 @@ let handles: Vec<_> = -ここでは新しい束縛、`handles`を導入します。今から新しいスレッドを作成していきますが、今から新しいスレッドを作成していきますが、 +ここでは新しい束縛、 `handles` を導入します。今から新しいスレッドを作成していきますが、 スレッドはそのスレッドを制御するハンドルを返すのでこの名前としました。後ほど議論する問題があるため、 -ここでは明示的な型アノテーションが必要となります。`_`は型プレースホルダです。 -つまり「`handles`は何らかの型のベクトルとするが、その型が何であるかはRustが解決せよ。」と言っています。 +ここでは明示的な型アノテーションが必要となります。 `_` は型プレースホルダです。 +つまり「 `handles` は何らかの型のベクトルとするが、その型が何であるかはRustが解決せよ。」と言っています。 ```rust,ignore philosophers.into_iter().map(|p| { @@ -506,8 +506,8 @@ philosophers.into_iter().map(|p| { -哲学者のリストに対して`into_iter()`を呼び出します。このメソッドは、哲学者の所有権を持つイテレータを生成します。 -スレッドに各要素を渡すため、このようにしました。イテレータに対して`map`を呼び出し、その引数として要素毎に順番に呼ばれるクロージャを渡します。 +哲学者のリストに対して `into_iter()` を呼び出します。このメソッドは、哲学者の所有権を持つイテレータを生成します。 +スレッドに各要素を渡すため、このようにしました。イテレータに対して `map` を呼び出し、その引数として要素毎に順番に呼ばれるクロージャを渡します。 ```rust,ignore thread::spawn(move || { @@ -520,17 +520,17 @@ philosophers.into_iter().map(|p| { -ここが並行実行される部分です。`thread::spawn`関数はクロージャを1つ引数にとり、新しいスレッド上でそのクロージャを実行します。 -このクロージャは特別なアノテーション、`move`を必要とします。これによりキャプチャする値の所有権がクロージャ内へと移動されます。 -今回のケースでは、`map`関数の変数`p`が該当します。 +ここが並行実行される部分です。 `thread::spawn` 関数はクロージャを1つ引数にとり、新しいスレッド上でそのクロージャを実行します。 +このクロージャは特別なアノテーション、 `move` を必要とします。これによりキャプチャする値の所有権がクロージャ内へと移動されます。 +今回のケースでは、 `map` 関数の変数 `p` が該当します。 -スレッド内では、`p`に対して`eat()`を呼び出しておしまいです。`thread::spawn`呼び出しの末尾にセミコロンを置かないことで、 +スレッド内では、 `p` に対して `eat()` を呼び出しておしまいです。 `thread::spawn` 呼び出しの末尾にセミコロンを置かないことで、 式としている点に注意してください。正しい戻り値を返すために、この区別は重要です。詳細については、 -[式 vs. 文][es]を参照ください。 +[式 vs. 文][es] を参照ください。 [es]: functions.html#expressions-vs-statements @@ -543,9 +543,9 @@ philosophers.into_iter().map(|p| { -最後に、`map`呼び出しの結果をまとめ上げます。`collect()`は何らかのコレクション型を生成しますが、要求する戻り値型アノテーションを必要とします: -ここでは`Vec`です。またその要素は`thread::spawn`呼び出しの戻り値、つまり各スレッドへのハンドルとなっています。 -フゥー! +最後に、 `map` 呼び出しの結果をまとめ上げます。 `collect()` は何らかのコレクション型を生成しますが、要求する戻り値型アノテーションを必要とします: +ここでは `Vec` です。またその要素は `thread::spawn` 呼び出しの戻り値、つまり各スレッドへのハンドルとなっています。 +フゥー! ```rust,ignore for h in handles { @@ -556,13 +556,13 @@ for h in handles { -`main()`の最後に、ハンドルへの`join()`呼び出しをループし、各スレッド実行が完了するまで実行をブロックします。 +`main()` の最後に、ハンドルへの `join()` 呼び出しをループし、各スレッド実行が完了するまで実行をブロックします。 これにより、プログラム終了前にスレッド処理が完了すると保証します。 -このプログラムを実行すると、哲学者たちが同不順に食事するさまが見られるでしょう! -マルチスレッド処理だ! +このプログラムを実行すると、哲学者たちが順不同に食事するさまが見られるでしょう! +マルチスレッド処理だ! ```text Judith Butler is eating. @@ -578,10 +578,10 @@ Michel Foucault is done eating. ``` -あれ、フォークはどこ行ったの?まだモデル化していませんでしたね。 +あれ、フォークはどこ行ったの?まだモデル化していませんでしたね。 -という訳で、新しい`struct`を作っていきましょう: +という訳で、新しい `struct` を作っていきましょう: ```rust use std::sync::Mutex; @@ -595,12 +595,12 @@ struct Table { -この`Table`は`Mutex`のベクトルを保持します。ミューテックスは並行処理を制御するための機構です: +この `Table` は `Mutex` のベクトルを保持します。ミューテックスは並行処理を制御するための機構です: その内容へ同時アクセスできるのは1スレッドに限定されます。これは正に今回のフォークに求められる性質です。 -単に保持するだけで、実際に値を使うあても無いため、ミューテックスの中身は空タプル`()`とします。 +単に保持するだけで、実際に値を使うあても無いため、ミューテックスの中身は空タプル `()` とします。 -プログラムで`Table`を使うよう変更しましょう: +プログラムで `Table` を使うよう変更しましょう: ```rust use std::thread; @@ -672,7 +672,7 @@ fn main() { -変更がたくさん!とはいえ、このイテレーションで、動作するプログラムが出来ました。細かく見ていきましょう: +変更がたくさん!とはいえ、このイテレーションで、動作するプログラムが出来ました。細かく見ていきましょう: ```rust,ignore use std::sync::{Mutex, Arc}; @@ -680,7 +680,7 @@ use std::sync::{Mutex, Arc}; -ここでは`std::sync`パッケージからもう一つの構造体: `Arc`を利用します。その詳細は使うときに説明します。 +ここでは `std::sync` パッケージからもう一つの構造体: `Arc` を利用します。その詳細は使うときに説明します。 ```rust,ignore struct Philosopher { @@ -695,9 +695,9 @@ struct Philosopher { -`Philosopher`に2つのフィールドを追加する必要があります。哲学者はそれぞれ2本のフォークを使います: -1本は左手に、もう1本は右手に。フォークの表現はベクトルのインデックスに対応するため、ここでは`usize`型を使います。 -2つの値は`Table`が保持する`forks`のインデクス値を表しています。 +`Philosopher` に2つのフィールドを追加する必要があります。哲学者はそれぞれ2本のフォークを使います: +1本は左手に、もう1本は右手に。フォークの表現はベクトルのインデックスに対応するため、ここでは `usize` 型を使います。 +2つの値は `Table` が保持する `forks` のインデクス値を表しています。 ```rust,ignore fn new(name: &str, left: usize, right: usize) -> Philosopher { @@ -711,7 +711,7 @@ fn new(name: &str, left: usize, right: usize) -> Philosopher { -インスタンス生成時に`left`と`right`の値が必要になりますから、`new()`を拡張しました。 +インスタンス生成時に `left` と `right` の値が必要になりますから、 `new()` を拡張しました。 ```rust,ignore fn eat(&self, table: &Table) { @@ -735,17 +735,17 @@ fn eat(&self, table: &Table) { -新しい行が3つあります。新しい引数`table`も追加しました。`Table`が保持するフォークのリストにアクセスし、 -フォークにアクセスするため`self.left`と`self.right`をインデクス値に用います。そのインデクスから`Mutex`が得られたら、 -`lock()`を呼び出します。ミューテックスが別スレッドから並行アクセスされていた場合は、有効になるまでブロックされるでしょう。 -またフォークを取上げる操作が一瞬で終わらないよう、最初のフォークを取上げてから2つ目のフォークを取上げるまでの間に`thread::sleep`を呼び出します。 +新しい行が3つあります。新しい引数 `table` も追加しました。 `Table` が保持するフォークのリストにアクセスし、 +フォークにアクセスするため `self.left` と `self.right` をインデクス値に用います。そのインデクスから `Mutex` が得られたら、 +`lock()` を呼び出します。ミューテックスが別スレッドから並行アクセスされていた場合は、有効になるまでブロックされるでしょう。 +またフォークを取上げる操作が一瞬で終わらないよう、最初のフォークを取上げてから2つ目のフォークを取上げるまでの間に `thread::sleep` を呼び出します。 -`lock()`呼び出しは失敗する可能性があり、その場合は、プログラムをクラッシュさせます。この状況は、ミューテックスが[「poisoned」][poison]状態、 -つまりロック保持中のスレッドがパニックした場合にしか発生しません。つまり今は起こりえないため、単に`unwrap()`を使っています。 +`lock()` 呼び出しは失敗する可能性があり、その場合は、プログラムをクラッシュさせます。この状況は、ミューテックスが [「poisoned」][poison] 状態、 +つまりロック保持中のスレッドがパニックした場合にしか発生しません。つまり今は起こりえないため、単に `unwrap()` を使っています。 [poison]: ../std/sync/struct.Mutex.html#poisoning @@ -754,14 +754,14 @@ fn eat(&self, table: &Table) { -もう一つの変わった点として: 結果を`_left`と`_right`と名づけました。このアンダースコアはなにもの? -ええと、ロック内ではこれらの値を_使う_予定がありません。単にロックを獲得したいだけです。 +もう一つの変わった点として: 結果を `_left` と `_right` と名づけました。このアンダースコアはなにもの? +ええと、ロック内ではこれらの値を _使う_ 予定がありません。単にロックを獲得したいだけです。 そうなると、Rustは値が未使用だと警告してくるでしょう。アンダースコアを使えば、Rustにこちらの意図を伝えることができ、 警告されなくなるのです。 -ロックの解放はどうしましょう?はい、`_left`と`_right`がスコープから抜けるとき、自動的に解放されます。 +ロックの解放はどうしましょう?はい、 `_left` と `_right` がスコープから抜けるとき、自動的に解放されます。 ```rust,ignore let table = Arc::new(Table { forks: vec![ @@ -777,8 +777,8 @@ fn eat(&self, table: &Table) { -続いて、`main()`では、新しい`Table`を作って`Arc`に包んでいます。「arc」は「アトミック参照カウント(atomic reference count)」を意味し、 -複数スレッドから`Table`を共有するために必要となります。共有するときは参照カウントを増やし、 +続いて、 `main()` では、新しい `Table` を作って `Arc` に包んでいます。「arc」は「アトミック参照カウント(atomic reference count)」を意味し、 +複数スレッドから `Table` を共有するために必要となります。共有するときは参照カウントを増やし、 各スレッドの終了時にはカウントを減らします。 ```rust,ignore @@ -799,9 +799,9 @@ let philosophers = vec![ -`Philosopher`のコンストラクタには`left`と`right`の値を渡す必要があります。ここではもう1つ細かい話がありますが、 -これは_非常に_重要な部分です。規則性という点では、最後以外は特に問題ありません。ムッシュ・フーコー(Foucault)は`4, 0`を引数にとるべきですが、 -代わりに、`0, 4`としています。これはデッドロックを防ぐためのものです。実は: 哲学者の一人は左利きだったのです! +`Philosopher` のコンストラクタには `left` と `right` の値を渡す必要があります。ここではもう1つ細かい話がありますが、 +これは_非常に_重要な部分です。規則性という点では、最後以外は特に問題ありません。ムッシュ・フーコー(Foucault)は `4, 0` を引数にとるべきですが、 +代わりに、 `0, 4` としています。これはデッドロックを防ぐためのものです。実は: 哲学者の一人は左利きだったのです! これは問題解決の一つのやり方ですが、私の見立てでは、最も単純な方法です。実引数の順番を変更すれば、デッドロックが生じるのを観測できるでしょう。 ```rust,ignore @@ -819,19 +819,19 @@ let handles: Vec<_> = philosophers.into_iter().map(|p| { -最後に、`map()`/`collect()`ループの中で、`table.clone()`を呼び出します。`Arc`の`clone()`メソッドにより参照カウントが増加し、 -スコープ外に出たときは、参照カウントが減算されます。これは、スレッドを跨いで`table`への参照が何個あるかを知るのに必要です。 +最後に、 `map()` / `collect()` ループの中で、 `table.clone()` を呼び出します。 `Arc` の `clone()` メソッドにより参照カウントが増加し、 +スコープ外に出たときは、参照カウントが減算されます。これは、スレッドを跨いで `table` への参照が何個あるかを知るのに必要です。 参照カウントを行わないと、いつ解放すればよいかが分からなくなってしまいます。 -ここでは新しい束縛`table`を導入して、古い方を覆い隠していることに気付くでしょう。 +ここでは新しい束縛 `table` を導入して、古い方を覆い隠していることに気付くでしょう。 これは2つの異なる名前を必要としないため、よく用いられる方法です。 -これで、プログラムが動くようになりました!2人の哲学者だけが同時に食事できるようになり、次のような出力がえられるでしょう: +これで、プログラムが動くようになりました!2人の哲学者だけが同時に食事できるようになり、次のような出力がえられるでしょう: ```text Gilles Deleuze is eating. @@ -847,4 +847,4 @@ Michel Foucault is done eating. ``` -おめでとう!古典並行処理問題をRustを使って実装できましたね。 +おめでとう!古典並行処理問題をRustを使って実装できましたね。