以前、私はいくつかの非常に単純なマルチスレッドコードを作成しましたが、実行中の途中でコンテキストスイッチが発生する可能性があることを常に認識していたため、共有変数へのアクセスを常に保護してきました。 CCriticalSectionクラスは、構築のクリティカルセクションに入り、破棄されます。私はこれがかなり攻撃的であることを知っており、クリティカルセクションに頻繁に、時にはひどく出入りします(たとえば、CCriticalSectionをよりタイトなコードブロック内に置くことができる関数の開始時)が、コードはクラッシュせず、十分に高速に実行されます。
仕事で私のマルチスレッドコードはよりタイトである必要があり、必要な最低レベルでのロック/同期のみです。
仕事で私はいくつかのマルチスレッドコードをデバッグしようとしていました、そして私はこれに出くわしました:
EnterCriticalSection(&m_Crit4);
m_bSomeVariable = true;
LeaveCriticalSection(&m_Crit4);
さて、m_bSomeVariable
Win32 BOOL(揮発性ではない)です。これは、私が知る限り、intとして定義されており、x86では、これらの値の読み取りと書き込みは単一の命令であり、コンテキストスイッチは命令境界で発生するため、必要はありません。この操作をクリティカルセクションと同期させるため。
この操作に同期が必要かどうかを確認するためにオンラインでさらに調査を行い、次の2つのシナリオを考え出しました。
- CPUがアウトオブオーダー実行を実装しているか、2番目のスレッドが別のコアで実行されており、更新された値が他のコアが確認できるようにRAMに書き込まれていません。と
- intは4バイトに揃えられていません。
ナンバー1は「volatile」キーワードで解決できると思います。VS2005以降では、C ++コンパイラはメモリバリアを使用してこの変数へのアクセスを囲み、使用する前に変数が常にメインシステムメモリに完全に書き込まれる/読み取られるようにします。
番号2確認できません。バイトアラインメントがなぜ違いを生むのかわかりません。x86命令セットはわかりませんがmov
、4バイトにアラインされたアドレスを指定する必要がありますか?そうでない場合は、指示を組み合わせて使用する必要がありますか?それは問題を引き起こすでしょう。
それで...
質問1:「volatile」キーワード(メモリバリアを使用し、このコードを最適化しないようにコンパイラにヒントを与えることを暗示する)を使用すると、プログラマはx86/x64変数の4バイト/8バイトを読み取り/間で同期する必要がなくなります。書き込み操作?
質問2:変数が4バイト/ 8バイトに整列されているという明示的な要件はありますか?
コードとクラスで定義された変数をさらに掘り下げました。
class CExample
{
private:
CRITICAL_SECTION m_Crit1; // Protects variable a
CRITICAL_SECTION m_Crit2; // Protects variable b
CRITICAL_SECTION m_Crit3; // Protects variable c
CRITICAL_SECTION m_Crit4; // Protects variable d
// ...
};
さて、私にはこれは過度に思えます。クリティカルセクションはプロセス間でスレッドを同期すると思ったので、ある場合はそのセクションに入ることができ、そのプロセス内の他のスレッドは実行できません。保護したい変数ごとにクリティカルセクションは必要ありません。クリティカルセクションにいる場合は、他に何も邪魔することはできません。
クリティカルセクションの外部から変数を変更できる唯一のことは、プロセスが別のプロセスとメモリページを共有し(それを実行できますか?)、他のプロセスが値を変更し始める場合だと思います。ミューテックスもここで役立ちます。名前付きミューテックスはプロセス間で共有されますか、それとも同じ名前のプロセスのみですか?
質問3:クリティカルセクションの分析は正しいですか?このコードはミューテックスを使用するように書き直す必要がありますか?他の同期オブジェクト(セマフォとスピンロック)を見てきましたが、ここの方が適していますか?
質問4:クリティカルセクション/ミューテックス/セマフォ/スピンロックはどこに最適ですか?つまり、どの同期問題に適用する必要があるかです。どちらかを選択すると、パフォーマンスが大幅に低下しますか?
そして、私たちがそれに取り組んでいる間、私は、スピンロックはシングルコアマルチスレッド環境では使用されるべきではなく、マルチコアマルチスレッド環境でのみ使用されるべきであることを読みました。それで、質問5:これは間違っていますか、そうでない場合は、なぜ正しいのですか?
返信ありがとうございます:)