1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Posted at

「実践Rustプログラミング入門」を参考に。
スレッド、並行処理系が気になったので実験。

p.85 スレッドを作る

Rustのスレッド間データ送受信方式は、

  1. 共有メモリ方式
  2. メッセージパッシング方式
    の2種類の方式があります、とのこと。標準的である。

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

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

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

main.rs
use std::thread;

fn main() {
    thread::spawn(|| {
        println!("Hello, world!");
    });
}
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が終了してしまうことがある。

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

main.rs
use std::thread;

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

    dbg!(handle.join());
}

実行する。

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のように_から始まる変数名にする。

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

実行する。

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

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

クロージャと言えば自由変数。と思ったら書籍にも記述されていた(pp.86-87)。

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

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キーワードを使え」となっているので追記する。

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が出ている)。

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年とのこと)。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?