0Pricing
Learn Rust Coding · レッスン

ArcとMutexで共有する

共有状態を安全に変更します。

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

共有状態の必要性

複数のスレッドで同じデータを読み取ったり更新したりしなければならない場合があります。所有権を1つのスレッドに移すだけでは不十分です。

Rustでは、Arcによってスレッド間で安全に所有権を共有でき、Mutexによって安全に変更できます。これらを組み合わせると、共有可能で変更可能な状態を実現できます。

Arc:アトミック参照カウント

Arcは、アトミックに参照カウントされることを意味します。Rcに似ていますが、カウンターにアトミック操作を使うため、スレッド間でも安全です。

Arcをクローンしてもデータはコピーされません。カウントが増え、同じ値を指す別のハンドルが返されるだけです。

use std::sync::Arc;

fn main() {
    let shared = Arc::new(vec![1, 2, 3]);
    let clone = Arc::clone(&shared);
    println!("{:?} {:?}", shared, clone);
}

スレッド間でArcを共有する

読み取り専用のデータを共有するには、スレッドごとにArcを1回クローンし、それぞれをムーブします。すべてのスレッドが同じアロケーションを指します。

ArcはSendかつSyncなので、問題なくコンパイルできます。

use std::sync::Arc;
use std::thread;

fn main() {
    let data = Arc::new(vec![10, 20, 30]);
    let mut handles = vec![];
    for i in 0..3 {
        let d = Arc::clone(&data);
        handles.push(thread::spawn(move || println!("{}", d[i])));
    }
    for h in handles { h.join().unwrap(); }
}

Arcだけでは読み取り専用

Arcは共有所有権を提供しますが、内部の値には共有された不変アクセスしかできません。

複数のスレッドが同時にArcを保持すると競合するため、Arcを直接使ってデータを変更することはできません。ロックによる内部可変性が必要です。

Mutex:相互排他

Mutexはデータを保護し、一度に1つのスレッドだけがアクセスできるようにします。アクセスするにはlockを呼び出します。

lockはResultを返し、アンラップするとスマートポインターのガードが得られます。他のスレッドはガードがドロップされるまでブロックします。

use std::sync::Mutex;

fn main() {
    let m = Mutex::new(0);
    {
        let mut guard = m.lock().unwrap();
        *guard += 5;
    }
    println!("{:?}", m);
}

ガードとRAII

lockが返す値はMutexGuardです。*でデリファレンスすると、内部のデータにアクセスできます。

ガードがスコープ外に出ると、ロックは自動的に解放されます。このRAII方式により、アンロックのし忘れを防げます。

ArcとMutexの組み合わせ

スレッド間で変更可能な状態を共有するには、MutexをArcの中に入れます。Arcが所有権を共有し、Mutexが変更を保護します。

Arc<Mutex<T>>というこのパターンは、Rustで共有可能かつ変更可能な状態を扱う標準的な方法です。

use std::sync::{Arc, Mutex};

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let c = Arc::clone(&counter);
    *c.lock().unwrap() += 1;
    println!("{}", *counter.lock().unwrap());
}

共有カウンター

ここでは10個のスレッドが共有カウンターをそれぞれインクリメントします。それぞれがArcをクローンし、Mutexをロックして、1を加算します。

ロックによってアクセスが順番に処理されるため、最終的な合計は必ず正確に10になります。

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    for _ in 0..10 {
        let c = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            *c.lock().unwrap() += 1;
        }));
    }
    for h in handles { h.join().unwrap(); }
    println!("{}", *counter.lock().unwrap());
}

クリティカルセクションを短く保つ

ロックを保持している間に実行されるコードがクリティカルセクションです。他のスレッドはそこで待機するため、短く保ってください。

ロックし、最小限の更新を行い、その後で解放します。ロックを保持したまま、負荷の高い計算やI/Oを行わないでください。

use std::sync::Mutex;

fn main() {
    let m = Mutex::new(Vec::new());
    {
        let mut v = m.lock().unwrap();
        v.push(1);
    } // lock released here
    println!("{:?}", m.lock().unwrap());
}

デッドロックとポイズニング

あるスレッドが同じMutexを2回ロックしたり、2つのスレッドが2つのミューテックスを逆の順序でロックしたりすると、デッドロックが発生して永遠に停止することがあります。

ロックを保持しているスレッドがパニックすると、Mutexはポイズン状態になり、その後のlock呼び出しはErrを返します。

多くの読み取りにはRwLock

書き込みよりも読み取りが大幅に多い場合は、RwLockのほうがMutexより適していることがあります。複数の読み取り側、または1つの排他的な書き込み側を同時に許可します。

共有アクセスにはreadを、排他的なアクセスにはwriteを使います。

use std::sync::RwLock;

fn main() {
    let lock = RwLock::new(5);
    {
        let r = lock.read().unwrap();
        println!("read {}", *r);
    }
    *lock.write().unwrap() += 1;
    println!("{}", *lock.read().unwrap());
}

クイックチェック

ArcとMutexについての理解度を確認しましょう。

まとめ

Arcはアトミック参照カウントによってスレッド間で所有権を共有しますが、不変アクセスしか許可しないことを学びました。

Mutexは変更を保護し、ドロップ時に解放されるガードを提供します。これらをArc<Mutex<T>>として組み合わせると、共有可能で変更可能な状態を扱えますが、デッドロックとポイズニングには注意が必要です。

次は、スレッドを結合して結果を集めます。

よくある質問

「ArcとMutexで共有する」レッスンは無料ですか?

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

「ArcとMutexで共有する」で何を学びますか?

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

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

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

「ArcとMutexで共有する」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

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