23

マルチスレッドアプリケーションをデバッグしていて、の内部構造を見つけましたCRITICAL_SECTION。CRITICAL_SECTIONのデータメンバーLockSemaphoreが面白いと思いました。

LockSemaphore自動リセットイベント(名前が示すようにセマフォではない)のように見え、オペレーティングシステムはCritcal Section、他のスレッドによってロックされているスレッドが最初に待機するときに、このイベントをサイレントに作成します。

さて、クリティカルセクションは常に速いのだろうか?イベントはカーネルオブジェクトであり、各クリティカルセクションオブジェクトはイベントオブジェクトに関連付けられていますCritical Section。Mutexなどの他のカーネルオブジェクトと比較して、どのように高速化できますか?また、内部イベントオブジェクトは実際にクリティカルセクションのパフォーマンスにどのように影響しますか?

:の構造は次のCRITICAL_SECTIONとおりです。

struct RTL_CRITICAL_SECTION
{
    PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
    LONG LockCount;
    LONG RecursionCount;
    HANDLE OwningThread;
    HANDLE LockSemaphore;
    ULONG_PTR SpinCount;
};
4

7 に答える 7

38

クリティカルセクションが「高速」であると彼らが言うとき、彼らは「それが別のスレッドによってまだロックされていないときにそれを取得するのは安い」という意味です。

[すでに別のスレッドによってロックされている場合は、速度はそれほど重要ではないことに注意してください ]

高速である理由は、カーネルに入る前に、InterlockedIncrementそれらのLONGフィールドの1つ(おそらくフィールド上LockCount)に相当するものを使用し、成功した場合は、カーネルに入らずに取得したロックを検討するためです。

APIは、InterlockedIncrementユーザーモードで「LOCKINC」オペコードとして実装されていると思います...つまり、カーネルへのリング遷移をまったく行わずに、競合のないクリティカルセクションを取得できます。

于 2009-05-12T16:12:04.983 に答える
28

パフォーマンス作業では、「常に」カテゴリに分類されるものはほとんどありません:)他のプリミティブを使用してOSクリティカルセクションに似たものを自分で実装すると、ほとんどの場合、速度が低下する可能性があります。

質問に答える最良の方法は、パフォーマンス測定を使用することです。OSオブジェクトのパフォーマンスは、シナリオによって大きく異なります。たとえば、競合が少ない場合、クリティカルセクションは一般に「高速」と見なされます。また、ロック時間がスピンカウント時間よりも短い場合も高速と見なされます。

決定する最も重要なことは、クリティカルセクションでの競合がアプリケーションの1次制限要因であるかどうかです。そうでない場合は、通常、クリティカルセクションを使用して、アプリケーションの主要なボトルネック(またはネック)に取り組みます。

クリティカルセクションのパフォーマンスがクリティカルである場合は、次のことを考慮することができます。

  1. 「ホット」クリティカルセクションのスピンロックカウントを慎重に設定します。パフォーマンスが最優先事項である場合、ここでの作業はそれだけの価値があります。スピンロックはユーザーモードからカーネルへの移行を回避しますが、CPU時間を猛烈な速度で消費することを忘れないでください。スピン中は、他にそのCPU時間を使用することはできません。ロックが十分に長く保持されている場合、回転しているスレッドは実際にブロックし、そのCPUを解放して他の作業を実行します。
  2. リーダー/ライターパターンがある場合は、スリムリーダー/ライター(SRW)ロックの使用を検討してください。ここでの欠点は、VistaおよびWindowsServer2008以降の製品でのみ使用できることです。
  3. クリティカルセクションで条件変数を使用して、ポーリングと競合を最小限に抑え、必要な場合にのみスレッドをウェイクアップできる場合があります。繰り返しますが、これらはVistaおよびWindowsServer2008以降の製品でサポートされています。
  4. Interlocked Singly Linked Lists(SLIST)の使用を検討してください。これらは効率的で「ロックフリー」です。さらに良いことに、これらはXPおよびWindowsServer2003以降の製品でサポートされています。
  5. コードを調べます。コードをリファクタリングしてインターロック操作を使用するか、同期と通信にSLISTを使用することで、「ホット」ロックを解除できる場合があります。

要約すると、ロックの競合があるチューニングシナリオは、困難な(しかし興味深い!)作業になる可能性があります。アプリケーションのパフォーマンスを測定し、ホットパスがどこにあるかを理解することに重点を置きます。Windowsパフォーマンスツールキットのxperfツールはここにあります:)Windows7および.NETFramework3.5SP1用のMicrosoftWindowsSDKでバージョン4.5をリリースしました(ISOはここにあり、Webインストーラーはここにあります)。xperfツールのフォーラムはここにあります。V4.5は、Win7、Vista、WindowsServer2008のすべてのバージョンを完全にサポートしています。

于 2009-05-12T15:53:37.947 に答える
4

CriticalSectionsの方が高速ですが、InterlockedIncrement / InterlockedDecrementの方が高速です。この実装の使用例LightweightLockフルコピーを参照してください。

于 2009-05-12T16:38:56.967 に答える
3

CriticalSectionsはしばらくの間(数ミリ秒)回転し、ロックが解放されているかどうかをチェックし続けます。スピンカウントが「タイムアウト」した後、カーネルイベントにフォールバックします。したがって、ロックの所有者がすぐに外れる場合は、カーネルコードに高価な移行を行う必要はありません。

編集:私のコードにいくつかのコメントがありました:どうやらMSヒープマネージャーは4000のスピンカウントを使用しています(msではなく整数の増分)

于 2009-05-12T15:28:52.493 に答える
1

これを見る方法は次のとおりです。

競合がない場合、Mutexのカーネルモードに移行する場合と比較して、スピンロックは非常に高速です。

競合がある場合、CriticalSectionは、Mutexを直接使用するよりもわずかにコストがかかります(スピンロック状態を検出するための余分な作業のため)。

つまり、加重平均に要約されます。加重は、呼び出しパターンの詳細によって異なります。そうは言っても、競合がほとんどない場合は、CriticalSectionが大きなメリットになります。一方、一貫して多くの競合がある場合は、Mutexを直接使用するよりもごくわずかなペナルティを支払うことになります。ただし、その場合、Mutexに切り替えることで得られるものは小さいので、競合を減らすことを試みたほうがよいでしょう。

于 2009-05-13T22:18:33.877 に答える
1

クリティカルセクションはカーネルオブジェクトではないため、クリティカルセクションはミューテックスよりも高速です。これは、現在のプロセスのグローバルメモリの一部です。Mutexは実際にはカーネルに存在し、mutextオブジェクトの作成にはカーネルスイッチが必要ですが、クリティカルセクションの場合はそうではありません。クリティカルセクションは高速ですが、スレッドが待機状態になるときにクリティカルセクションを使用しているときにカーネルスイッチが発生します。これは、スレッドのスケジューリングがカーネル側で行われるためです。

于 2015-01-06T09:20:48.630 に答える
0

私の経験と実験から、実装CRITICAL_SECTIONに比べて非常に遅いです。pthreads

同じコードをpthread実装と比較した場合、ロック/ロック解除の数が多い場合、スレッドの切り替えが約10倍遅くなることを非常に意味します。

したがって、クリティカルセクションを二度と使用することはありません。pthreadはMSWindowsでも利用可能であり、最終的にパフォーマンスの悪夢は終わりました。

于 2021-02-23T10:17:20.753 に答える