「最新の C++ チュートリアル」メモ (5-7)

5 スマート ポインタとメモリ管理

5.1 RAII と参照カウント

従来の C++ では、リソースを手動で解放することを「忘れない」ことが常にベスト プラクティスであるとは限りません。リソースの解放を忘れてリークが発生する可能性が高いためです。したがって、通常は、オブジェクトの場合、コンストラクターでスペースを申請し、デストラクター (スコープを離れるときに呼び出されます) でスペースを解放します。これは、RAII リソースの取得および初期化テクノロジとよく呼ばれるものです。

すべてには例外があります。空きストレージにオブジェクトを割り当てる必要が常にあります。従来の C++ では、リソースを解放することを「記憶」するために new と delete を使用する必要があります。C++11 ではスマート ポインターの概念が導入され、参照カウントの考え方が使用されているため、プログラマーは手動でメモリを解放する必要がなくなりました。これらのスマート ポインターには std::shared_ptr/std::unique_ptr/std::weak_ptr が含まれており、これらを使用するにはヘッダー ファイル メモリを含める必要があります。

5.2 std::shared_ptr

std::shared_ptr は、オブジェクトを指すshared_ptrの数を記録できるスマート ポインターです。これにより、明示的に delete を呼び出す必要がなくなり、参照カウントがゼロになるとオブジェクトは自動的に削除されます。

しかし、これだけでは十分ではありません。std::shared_ptr を使用しても、呼び出すために new を使用する必要があり、コードが多少非対称になります。

std::make_shared を使用すると、 new の明示的な使用を排除できるため、 std::make_shared は受信パラメータにオブジェクトを割り当てて作成し、このオブジェクト型の std::shared_ptr ポインタを返します。

5.3 std::unique_ptr

std::unique_ptr は排他的なスマート ポインターであり、他のスマート ポインターが同じオブジェクトを共有することを禁止するため、コードの安全性が確保されます。

排他的であるため、つまりコピーすることができません。ただし、std::move を使用して他の unique_ptr に転送できます。

5.4 std::weak_ptr

std::weak_ptr は弱参照です (それに比べて、std::shared_ptr は強参照です)。弱い参照によって参照カウントが増加することはありません。

std::weak_ptr には * 演算子と -> 演算子がないため、リソースを操作できません。std::shared_ptr が存在するかどうかを確認するために使用でき、リソースが解放されていない場合は、そのexpire() メソッドが false を返すことができます。それ以外の場合は true を返します。さらに、元のオブジェクトを指す std::shared_ptr ポインタを取得するために使用することもでき、元のオブジェクトが存在しない場合、その lock() メソッドは元のオブジェクトを指す std::shared_ptr ポインタを返します。 release してから元のオブジェクトのリソースにアクセスします。それ以外の場合は nullptr を返します。

6つの正規表現

この章では紹介することは何もないので読み飛ばしてください。

7 並列処理と同時実行性

7.1 並列の基本

std::thread は実行スレッド インスタンスの作成に使用されるため、すべての同時プログラミングの基礎となり、使用する場合はヘッダー ファイルを含める必要があります。スレッドを取得するための get_id() など、多くの基本的なスレッド操作が提供されます。作成されたスレッドの ID 、join() を使用してスレッドが終了する (そのスレッドに参加する) などを待ちます。

7.2 ミューテックスとクリティカルセクション

私たちはオペレーティング システムやデータベースの知識で並行性テクノロジの基礎を学び、ミューテックスはそのコアの 1 つです。C++11 ではミューテックス関連のクラスが導入され、関連する関数はすべてミューテックス ヘッダー ファイルに配置されます。

std::mutex は C++11 の最も基本的なミューテックス クラスです。ミューテックスは std::mutex をインスタンス化することで作成でき、そのメンバー関数 lock() によってロックおよびロック解除できます。ただし、実際にコードを記述するプロセスでは、メンバー関数を直接呼び出さないことをお勧めします。メンバー関数を呼び出すには、各クリティカル セクションの出口でunlock()を呼び出す必要があり、当然例外も含まれるためです。現時点では、C++11 はミューテックス用の RAII 構文テンプレート クラス std::lock_guard も提供します。RAII は、コードの単純さを失うことなく、コードの例外安全性を保証します。

C++ では、すべてのスタック オブジェクトが存続期間の終わりに破棄されることが保証されているため、そのようなコードは例外安全でもあります。Critical_section() が正常に戻るか途中で例外をスローするかに関係なく、スタック ロールバックが発生し、unlock() が自動的に呼び出されます。

そして、 std::unique_lock は std::lock_guard に対して相対的に表示され、 std::unique_lock はより柔軟で、 std::unique_lock のオブジェクトは排他的所有権を持ちます (他の unique_lock オブジェクトは同時にミューテックス オブジェクトの所有権を所有しません)。ミューテックス オブジェクトのロックおよびロック解除操作。したがって、同時プログラミングでは、std::unique_lock を使用することをお勧めします。

std::lock_guard はロックとロック解除を明示的に呼び出すことはできませんが、 std::unique_lock は宣言後の任意の位置で呼び出すことができるため、ロックの範囲を減らし、より高い同時実行性を実現できます。

条件変数 std::condition_variable::wait を使用する場合は、パラメーターとして std::unique_lock を使用する必要があります。

7.3 先物

Future は std::future で表され、非同期操作の結果にアクセスする方法を提供しますが、この文は非常に理解しにくいです。この機能を理解するには、C++11 より前のマルチスレッドの動作を理解する必要があります。

想像してみてください。メイン スレッド A が、期待される特定のタスクを実行するために新しいスレッド B を作成し、結果を返したいと考えているとします。現時点では、スレッド A は他のことで忙しく、B の結果を検討する時間がない可能性があるため、当然、スレッド B の結果を特定の時刻に取得したいと考えます。

C++11 の std::future が導入される前は、スレッド A を作成し、スレッド A でタスク B を開始し、準備が完了したらイベントを送信し、結果をグローバル変数に保存するのが一般的なアプローチでした。そして、メイン関数スレッド A は他の処理を行っており、結果が必要な場合にはスレッド待機関数を呼び出して実行結果を取得します。

C++11 で提供される std::future はこのプロセスを簡素化し、非同期タスクの結果を取得するために使用できます。当然、スレッド同期の単純な手段、つまりバリアであることは容易に想像できます。

7.4 条件変数

条件変数 std::condition_variable はデッドロックを解決するために生まれ、相互排他操作では不十分な場合に導入されました。たとえば、スレッドは実行を続行する前に特定の条件が true になるまで待機する必要がある場合があり、ビジー待機ループによって他のすべてのスレッドがクリティカル セクションに入ることができなくなり、条件が true になるとデッドロックが発生する場合があります。したがって、condition_variable インスタンスは、主にデッドロックを回避するために待機中のスレッドをウェイクアップするために作成されます。std::condition_variable の notify_one() はスレッドを起動するために使用され、notify_all() はすべてのスレッドに通知します。

プロデューサでnotify_one()を使用することはできますが、実際にはここで使用することはお勧めできません。複数のコンシューマの場合、コンシューマの実装は単純に保持しているロックを放棄するためです。はい、これにより、他のコンシューマがこのロックをめぐって競合するため、複数のコンシューマ間の同時実行性がより有効に活用されます。そうは言っても、実際には、std::mutex の排他性のため、複数のコンシューマーがキュー内で生成されたコンテンツを本当の意味で消費することは期待できず、さらにきめ細かなアプローチが必要です。

7.5 アトミック操作とメモリモデル

おすすめ

転載: blog.csdn.net/YuhsiHu/article/details/131987090