最新の C++ でのマルチスレッド

新しい C++11 標準により、C++ はマルチコア アーキテクチャの初めての課題に直面します。 2011 年に公開された標準では、複数のスレッドが存在する場合に C++ プログラムがどのように動作する必要があるかが定義されています。 C++11 のマルチスレッド機能は、2 つのコンポーネントで構成されています。これは一方では定義済みのメモリ モデルであり、他方では標準化されたスレッド インターフェイスです。

明確に定義されたメモリ モデル

定義されたメモリ モデルは、マルチスレッド プログラミングが C++ で意味を持つために必要な基礎です。したがって、記憶モデルは次の質問に答えなければなりません。

<オール>
  • アトミック操作とは
  • どの操作順序が保証されていますか?
  • 操作のメモリ効果はいつ表示されますか?
  • To 1: アトミック操作は、データベース理論で有名な ACID イディオムの最初の 3 文字に従う操作です。アトミック操作はアトミック (A) であり、ある一貫性のある (C) 状態から次の状態に移行し、分離して実行されます (I)。これは特に、他のスレッドがアトミック操作の中間状態を監視できないことを意味します。インクリメントatomVar++は、アトミック操作の一貫性と分離を非常にうまく示しています。 atomVar がアトミック変数の場合、atomVar は古い値または新しい値のみを持つことができます。変数 atomVar の一貫性は、ある状態から別の状態にのみ変化し、分離されていること、別のスレッドが中間値を観察できないことです。

    トゥ 2: プログラムをアセンブラー命令に変換するコンパイラーと、アセンブラー命令を実行するプロセッサーの両方が、操作を再編成できます。ほとんどの場合、これはパフォーマンス上の理由によるものです。さらに、ストレージ (キャッシュ) のさまざまな層により、操作の結果が遅れて提供される可能性があります。

    トゥ 3: あるスレッドが別のスレッドよりも後で変数の操作を確認する可能性は十分にあるため、スレッドは特定の規則に従わなければなりません。

    標準化されたスレッド インターフェース

    C++11 の標準化されたスレッド インターフェイスは、次のコンポーネントで構成されています。

    <オール>
  • スレッド
  • タスク
  • スレッド ローカル データ
  • 条件変数
  • To 1: スレッドは、マルチスレッド プログラミングの基本的な構成要素です。それらは自律的に作業を行い、引数によってパラメーター化され、共有変数を介して他のスレッドと対話します。

    2 まで :タスクは比較的現代的な概念です。タスクは、通信チャネルによって接続された 2 つのコンポーネントで構成されます。チャネルのエンドポイントとしての 1 つのコンポーネントが結果を生成し、もう一方のエンドポイントがそれを消費します。プロデューサは Promise、コンシューマ Future と呼ばれます。

    3まで :スレッド ローカル データは、名前から容易に推測できるような、1 つのスレッドに明示的に属するデータです。

    4まで :Condition 変数により、プロデューサー/コンシューマー ワークフローを実装できます。コンシューマーは、プロデューサーの通知を待って、作業を続行できます。

    C++17 と C++20 には何が付属しますか?

    次の C++ 標準は、2017 年と 2020 年に予定されています。C++17 と C++20 は、既存の標準のマルチスレッド機能に関する多くの拡張機能で構成されます。既存の機能は非常に基本的なものだからです。これらの変更には、次の 3 つの興味深い機能が含まれる可能性があります:

    <オール>
  • ラッチとバリア
  • トランザクション メモリ
  • 標準テンプレート ライブラリ (STL) のアルゴリズムの自動並列化またはベクトル化
  • 1に :ラッチとバリアはセマフォに似ています。

    2 まで :トランザクション メモリとは、簡単に言えば、コードに適用された ACID の考え方 (最初の 3 文字のみ) です。つまり、コードにはトランザクション メモリとして注釈が付けられ、コードは他のスレッドと同期することなく楽観的に実行されます。トランザクションの終了時に、初期条件がまだ有効である場合にのみ、結果が公開されます。そうでない場合、結果の結果は拒否され、トランザクションが再度実行されます。重要な領域はミューテックスによって常にロックされていますが、トランザクションはロックされていませんが、結果が破棄される可能性があります。クリティカル エリアとは、一度に 1 つのスレッドしか入ることができないコードのセクションです。

    3まで :並列化アルゴリズムはコンテナーの操作を複数のスレッドに分散させますが、ベクトル化アルゴリズムはコンテナーの複数の要素の操作を 1 つのステップで実行します。

    マイプラン

    次のいくつかの記事では、C++ メモリ モデルのコンポーネントと標準化されたスレッド インターフェイスについて詳しく見ていきます。私の焦点は、すべての詳細を詳しく説明することではありません。詳細は、現在の C++ 標準 14882:2014 または Web ページ cppreference.com で十分に文書化されています。

    特に今後の記事では、マルチスレッド プログラムを扱う際の典型的なエラーを紹介し、もちろん解決策を提案することに焦点を当てます。この目的のために、問題と解決策を理解するための理論を必要なだけ取り入れます。標準化されたスレッド インターフェイスから始めます。

    次は?

    次の投稿では、スレッドの作成について扱います。