0Pricing
Learn Rust Coding · レッスン

スレッドを生成する

コードを並行して実行します。

「スレッドを生成する」はCoddyKit上の無料Learn Rust Codingレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLearn Rust Coding学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Learn Rust Codingコースには全4レッスンが含まれています。

スレッドとは

スレッドを使うと、プログラムでコードを並行して実行できます。オペレーティングシステムは複数のスレッドをスケジュールできるため、処理を重ねて進められます。

Rust の標準ライブラリでは、std::thread モジュールを通じてスレッドを利用できます。これはネイティブ OS スレッドで、1:1 スレッドと呼ばれることもあります。

このレッスンでは、新しいスレッドを開始し、その実行を制御する方法を学びます。

thread::spawn でスレッドを生成する

thread::spawn を呼び出し、クロージャを渡すことで新しいスレッドを作成します。クロージャには、新しいスレッドで実行するコードを記述します。

呼び出しはすぐに JoinHandle を返し、生成されたスレッドはバックグラウンドで実行されます。

use std::thread;

fn main() {
    thread::spawn(|| {
        println!("hello from a thread");
    });
    println!("hello from main");
}

main が先に終了する場合

main が戻ると、生成されたスレッドがまだ実行中でもプロセス全体が終了します。

そのため、上のプログラムでは main のメッセージしか出力されない可能性があります。プロセスが終了する前に、バックグラウンドスレッドが実行する機会を得られないことがあるためです。

スレッドの終了を待つ方法が必要です。

join で待機する

spawn が返す JoinHandle には join メソッドがあります。これを呼び出すと、生成されたスレッドが終了するまで現在のスレッドがブロックされます。

これにより、main の処理が続行する前に、生成されたスレッドが最後まで実行されることが保証されます。

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        println!("worker done");
    });
    handle.join().unwrap();
    println!("main done");
}

出力のインターリーブ

2つのスレッドが同時に実行されると、出力の順序が予測できない形で入り混じることがあります。スケジュールは OS が決定します。

同じプログラムを2回実行しても、順序が異なる場合があります。同期なしに特定の順序を前提にしてはいけません。

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..4 {
            println!("thread: {}", i);
        }
    });
    for i in 1..4 {
        println!("main: {}", i);
    }
    handle.join().unwrap();
}

sleep で一時停止する

Duration を受け取る thread::sleep を使って、スレッドを一時停止できます。これにより CPU が解放され、他のスレッドが処理を進められます。

スリープは例でインターリーブを分かりやすくするのには便利ですが、実際の同期処理には使わないでください。

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

fn main() {
    thread::spawn(|| {
        for i in 1..4 {
            println!("spawned: {}", i);
            thread::sleep(Duration::from_millis(1));
        }
    });
    thread::sleep(Duration::from_millis(10));
}

複数のスレッドを生成する

ループ内で複数のスレッドを生成し、そのハンドルをベクターに集めることができます。

後でベクターを反復処理して各ハンドルに対して join を呼び出し、プログラムが終了する前にすべてのスレッドが完了するようにします。

use std::thread;

fn main() {
    let mut handles = vec![];
    for id in 0..3 {
        let h = thread::spawn(move || {
            println!("thread {}", id);
        });
        handles.push(h);
    }
    for h in handles {
        h.join().unwrap();
    }
}

Builder でスレッドに名前を付ける

thread::Builder 型を使うと、スレッドを生成する前に設定できます。名前とスタックサイズを指定できます。

名前付きスレッドを使うと、パニックメッセージやデバッグ情報が読みやすくなります。

use std::thread;

fn main() {
    let h = thread::Builder::new()
        .name("worker".into())
        .spawn(|| {
            println!("running in named thread");
        })
        .unwrap();
    h.join().unwrap();
}

パニックはスレッド内にとどまる

生成されたスレッドでパニックが発生しても、デフォルトではプログラム全体がクラッシュすることはありません。パニックはそのスレッド内にとどまります。

パニックしたスレッドに対して join を呼び出すと、Err が返されます。これにより、親スレッドで失敗を検出できます。

use std::thread;

fn main() {
    let h = thread::spawn(|| {
        panic!("boom");
    });
    let result = h.join();
    println!("joined, is_err = {}", result.is_err());
}

現在のスレッド情報

thread::current を使って、実行中のスレッドを調べることができます。これはハンドルを返し、その name メソッドで省略可能なスレッド名を取得できます。

main スレッドも実際のスレッドで、通常は main という名前が付いています。

use std::thread;

fn main() {
    let current = thread::current();
    println!("name: {:?}", current.name());
}

スレッドから値を返す

spawn に渡したクロージャは値を返すことができます。その値は、join を呼び出すと Ok にラップされて返されます。

別のスレッドで計算を行い、後から結果を読み取るための簡単な方法です。

use std::thread;

fn main() {
    let h = thread::spawn(|| {
        let sum: i32 = (1..=10).sum();
        sum
    });
    let total = h.join().unwrap();
    println!("total = {}", total);
}

確認問題

スレッドの生成についての理解度を確認しましょう。

まとめ

thread::spawn とクロージャを使ってスレッドを開始する方法を学びました。thread::spawn は JoinHandle を返します。

join を呼び出すと完了を待機し、戻り値やパニックを取得できます。スレッド間の出力は予測できない順序で入り混じることがあり、Builder を使うとスレッドに名前を付けられます。

次は、生成するスレッドにデータを移動する方法を学びます。

よくある質問

「スレッドを生成する」レッスンは無料ですか?

はい。「スレッドを生成する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Learn Rust Codingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Learn Rust Codingコースには全4レッスンが含まれています。

「スレッドを生成する」で何を学びますか?

コードを並行して実行します。 ブラウザで直接実行するハンズオンコードでLearn Rust Codingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Learn Rust Codingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLearn Rust Codingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「スレッドを生成する」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLearn Rust Codingレッスンでコードを書いて実行できますか?

はい。すべてのLearn Rust Codingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. スレッドを生成する
  2. データをスレッドに移動する
  3. ArcとMutexで共有する
  4. 結合して結果を集める
← Learn Rust Codingに戻る