「実践Rustプログラミング入門」に入門する(8日目)Chapter3 Rustの基本　pp.85-88



[「実践Rustプログラミング入門」](https://www.shuwasystem.co.jp/book/9784798061702.html)を参考に。
スレッド、並行処理系が気になったので実験。

# p.85 スレッドを作る

Rustのスレッド間データ送受信方式は、
1. 共有メモリ方式
2. メッセージパッシング方式
の2種類の方式があります、とのこと。標準的である。

新規にプロジェクトを作る。

```shell
PS > cargo new thread
     Created binary (application) `thread` package
```

main.rsをp.85に従い、書き換える。`thread`は標準ライブラリ。`spawn`の引数`|| {body}`はクロージャ。

```rust:main.rs
use std::thread;

fn main() {
    thread::spawn(|| {
        println!("Hello, world!");
    });
}
```

```shell
PS thread> cargo run
   Compiling thread v0.1.0 (\thread)
    Finished dev [unoptimized + debuginfo] target(s) in 1.34s
     Running `target\debug\thread.exe`
PS thread> cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target\debug\thread.exe`
PS thread> cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target\debug\thread.exe`
PS thread> cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target\debug\thread.exe`
Hello, world!
```

何回か試すと、メッセージが出る。threadなので、println!が動作する前に、mainが終了してしまうことがある。

必ず表示させるためのコードは以下。

```rust:main.rs
use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        println!("Hello, world!");
    });

    dbg!(handle.join());
}
```

実行する。

```shell
PS thread> cargo run
   Compiling thread v0.1.0 (thread)
warning: unused `std::result::Result` that must be used
 --> src\main.rs:8:5
  |
8 |     dbg!(handle.join());
  |     ^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_must_use)]` on by default
  = note: this `Result` may be an `Err` variant, which should be handled
  = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

warning: 1 warning emitted

    Finished dev [unoptimized + debuginfo] target(s) in 1.14s
     Running `target\debug\thread.exe`
Hello, world!
[src\main.rs:8] handle.join() = Ok(
    (),
)
```

「Resultをきちんと使いなさい」と警告が出るが、実行はされる(p.86)。
きちんと使うと以下の通り。使わないことが分かっている変数は`_code`のように`_`から始まる変数名にする。

```rust:main.rs
use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        println!("Hello, world!");
    });

    match handle.join() {
        Ok(_code) => println!("OK"),
        Err(_err) => println!("Err"),
    };
}
```
実行する。

```shell
PS thread> cargo run
   Compiling thread v0.1.0 (thread)
    Finished dev [unoptimized + debuginfo] target(s) in 0.82s
     Running `target\debug\thread.exe`
Hello, world!
OK
```

想定通りの実行結果となる。

[クロージャ](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%B8%E3%83%A3)と言えば自由変数。と思ったら書籍にも記述されていた(pp.86-87)。

```rust:main.rs
use std::thread;

fn main() {
    let mut handles = Vec::new();

    for x in 0..10 {
        handles.push(thread::spawn(|| {
            println!("Hello, world! {}", x);
        }));
    }

    for handle in handles {
        match handle.join() {
            Ok(_code) => println!("OK"),
            Err(_err) => println!("Err"),
        };
    }
}
```

ここまで書いたところで、クロージャ先頭でエラーが出る。
![20200908_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2059/232340ef-016f-3f6f-a490-f6011b064873.png)


```shell
PS thread> cargo run
   Compiling thread v0.1.0 (thread)
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
 --> src\main.rs:7:36
  |
7 |         handles.push(thread::spawn(|| {
  |                                    ^^ may outlive borrowed value `x`
8 |             println!("Hello, world! {}", x);
  |                                          - `x` is borrowed here
  |
note: function requires argument type to outlive `'static`
 --> src\main.rs:7:22
  |
7 |           handles.push(thread::spawn(|| {
  |  ______________________^
8 | |             println!("Hello, world! {}", x);
9 | |         }));
  | |__________^
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword    
  |
7 |         handles.push(thread::spawn(move || {
  |                                    ^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0373`.
error: could not compile `thread`.

To learn more, run the command again with --verbose.
```

`cargo run`でもエラー。この辺りは動的言語のように緩く対応してくれない(システムプログラミング言語なので、適当に対応されると困る)。

p.87にもあるが、エラーメッセージ内でも「moveキーワードを使え」となっているので追記する。

```rust:main.rs
use std::thread;

fn main() {
    let mut handles = Vec::new();

    for x in 0..10 {
        handles.push(thread::spawn(move || {
            println!("Hello, world! {}", x);
        }));
    }

    for handle in handles {
        match handle.join() {
            Ok(_code) => println!("OK"),
            Err(_err) => println!("Err"),
        };
    }
}
```

実行する。終了部分をいじってあるので、p.88とは出力が違っている(OKが出ている)。

```shell
PS thread> cargo run
   Compiling thread v0.1.0 (thread)
    Finished dev [unoptimized + debuginfo] target(s) in 1.00s
     Running `target\debug\thread.exe`
Hello, world! 0
Hello, world! 1
Hello, world! 2
Hello, world! 3
Hello, world! 4
Hello, world! 5
Hello, world! 6
Hello, world! 7
Hello, world! 8
Hello, world! 9
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
```

良い感じ。

# 振り返り
スレッドプログラミングがこんなにあっさりとできる。pthreadができる前からプログラミングしていた世代には感動的なのではないか([pthreadができたのは1995年とのこと](https://docs.oracle.com/cd/E19253-01/819-0390/mtintro-75924/index.html))。