std::mutex、lock_guard、unique_lock
mutexとRAIIによるロックヘルパーで共有状態を保護します。
「std::mutex、lock_guard、unique_lock」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。
なぜミューテックスが必要なのか
複数のスレッドが同じデータにアクセスすると、データを奪い合う競合が発生します。ミューテックスは相互排他を保証し、一度に1つのスレッドだけがロックを保持できるようにします。
std::mutexの基本
構築し、ロックし、アンロックします。手動ロックはエラーが起こりやすいため、必ずRAIIヘルパーを使用してください。
#include <mutex>
std::mutex mtx;
mtx.lock();
// critical section
mtx.unlock();std::lock_guard:RAIIロック
最もシンプルなRAIIロックです。コンストラクターでロックし、デストラクターでアンロックします。例外を送出しないクリティカルセクションに最適です。
std::mutex mtx;
int counter = 0;
void increment() {
std::lock_guard<std::mutex> lock(mtx);
++counter;
}std::scoped_lock(C++17)
lock_guardに似ていますが、複数のミューテックスをデッドロックなしで一度にロックできます。現代的なコードではこちらを優先してください。
#include <mutex>
std::scoped_lock lock(mtx1, mtx2, mtx3); // locks all atomicallystd::unique_lock:柔軟なロック
lock_guardより多くの機能を備えています:
- スコープの途中でアンロックと再ロックができます
- ムーブできます(所有権を移譲できます)
- 条件変数と組み合わせて使用します
std::unique_lock<std::mutex> lock(mtx);
lock.unlock(); // release temporarily
// ... do something without the lock ...
lock.lock(); // reacquireデッドロックの回避
2つのスレッドが異なる順序でロックを取得すると、デッドロックが発生する可能性があります。常に一貫した全体順序で取得するか、複数のミューテックスに対してstd::scoped_lockを使用してください。
複数のミューテックスに対するstd::lock
C++17より前では、複数のミューテックスをアトミックに取得するためにstd::lockを使用します。C++17のstd::scoped_lockのほうが簡潔です。
再帰ミューテックス
std::recursive_mutexを使うと、1つのスレッドが同じミューテックスを複数回ロックできます。通常は設計上の問題の兆候なので、代わりにリファクタリングしてください。
try_lockとtimed_mutex
ロックが保持されている場合、try_lockは直ちに戻ります。std::timed_mutexは、時間制限付きのロック試行をサポートします。
リーダー・ライターロック
std::shared_mutex(C++17)を使うと、複数の読み取り側が同時にアクセスするか、1つの書き込み側が排他的にアクセスできます。読み取りが多い処理に使用します。
std::shared_mutex sm;
void read() { std::shared_lock lk(sm); /* read */ }
void write() { std::unique_lock lk(sm); /* write */ }粒度のトレードオフ
ロックの粒度が粗すぎると並行性が損なわれます。細かすぎるとオーバーヘッドが増加します。プロファイリングを行って調整してください。
ロックフリーの代替手段
競合が激しい状況では、ロックフリーのデータ構造(アトミック操作、ロックフリーキュー)を検討してください。正しく記述するのははるかに難しいため、必要性を確認し、検証できる場合にのみ使用します。
簡単な確認
複数のミューテックスを一度にロックする場合、どのRAIIロックを優先すべきですか?
まとめ
シンプルなクリティカルセクションにはstd::lock_guard、複数のミューテックスにはstd::scoped_lock、条件変数や手動アンロックなどの柔軟性が必要な場合にはstd::unique_lockを使用します。必ずRAIIを使用し、lock/unlockを手動で呼び出さないでください。
よくある質問
「std::mutex、lock_guard、unique_lock」レッスンは無料ですか?
はい。「std::mutex、lock_guard、unique_lock」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。
「std::mutex、lock_guard、unique_lock」で何を学びますか?
mutexとRAIIによるロックヘルパーで共有状態を保護します。 ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C++ Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「std::mutex、lock_guard、unique_lock」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC++ Academyレッスンでコードを書いて実行できますか?
はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- std::threadのjoinとdetach
- std::mutex、lock_guard、unique_lock
- 条件変数とワーカーパターン
- std::asyncとstd::futureの基本