6

このシナリオのロックの問題を解決する必要があります。

  1. マルチCPUシステム。
  2. すべてのCPUは、共通の(ソフトウェア)リソースを使用します。
  3. リソースへの読み取り専用アクセスは非常に一般的です。(着信ネットワークパケットの処理)
  4. 書き込みアクセスの頻度ははるかに低くなります。(ほとんどの構成変更のみ)。

現在read_lock_bhwrite_lock_bh(スピンロック)メカニズムを使用しています。問題は、CPUが多いほど、ライターのコンテキストでソフトロックアップが発生することです。

この本の並行性の章を読みましたが、スピンロックを使用するときにリーダーとライターのどちらが優先されるかを完全には理解できませんでした。

したがって、質問は次のとおりです。

  1. Linuxスピンロックメカニズムはリーダー/ライター/それらのどれも優先しませんか?
  2. シナリオでこれらのソフトロックアップを回避するために使用できるより良いメカニズムはありますか、または現在のソリューションを使用している間、ライターがロックを取得しようとするたびにライターを優先する方法はありますか?

ありがとう、ニル

4

3 に答える 3

6

これは、あなたが探しているかもしれないEssential Linux Device Driversからの直接の引用です。最後にRCUを扱う部分が気になるところかもしれません。

リーダー/ライター ロック

別の特殊な同時実行制御メカニズムは、スピンロックのリーダー/ライター バリアントです。クリティカル セクションの使用法が、個別のスレッドが共有データ構造からの読み取りまたは書き込みのいずれかを行うが、両方は行わない場合、これらのロックは自然に適合します。重要な領域内で複数のリーダー スレッドを同時に使用できます。リーダーのスピンロックは次のように定義されます。

rwlock_t myrwlock = RW_LOCK_UNLOCKED;

read_lock(&myrwlock);             /* Acquire reader lock */
/* ... Critical Region ... */
read_unlock(&myrwlock);           /* Release lock */

ただし、ライター スレッドがクリティカル セクションに入ると、他のリーダーまたはライター スレッドが内部に入ることはできません。ライターのスピンロックを使用するには、次のように記述します。

rwlock_t myrwlock = RW_LOCK_UNLOCKED;

write_lock(&myrwlock);            /* Acquire writer lock */
/* ... Critical Region ... */
write_unlock(&myrwlock); /* Release lock */

net/ipx/ipx_route.cリーダー/ライター スピンロックの実際の例として、 にある IPX ルーティング コードを見てください。と呼ばれるリーダー/ライター ロックipx_routes_lockは、IPX ルーティング テーブルを同時アクセスから保護します。パケットを転送するためにルーティング テーブルを検索する必要があるスレッドは、リーダー ロックを要求します。ルーティング テーブルのエントリを追加または削除する必要があるスレッドは、ライター ロックを取得します。通常、ルーティング テーブルの更新よりもルーティング テーブルのルックアップのインスタンスの方がはるかに多いため、これによりパフォーマンスが向上します。

通常のスピンロックと同様に、リーダー/ライター ロックにも対応する irq バリアント ( read_lock_irqsave()read_lock_irqrestore()write_lock_irqsave()、および ) がありwrite_lock_irqrestore()ます。これらの関数のセマンティクスは、通常のスピンロックのセマンティクスに似ています。

2.6 カーネルで導入されたシーケンス ロックまたは seqlock は、リーダーよりもライターが優先されるリーダー/ライター ロックです。これは、変数への書き込み操作が読み取りアクセス数をはるかに上回る場合に役立ちます。例として jiffies_64、この章で前述した変数があります。ライター スレッドは、クリティカル セクション内にいる可能性のあるリーダーを待機しません。このため、リーダー スレッドは、クリティカル セクション内のエントリが失敗したことを検出し、再試行する必要がある場合があります。

u64 get_jiffies_64(void) /* Defined in kernel/time.c */
{
   unsigned long seq;
   u64 ret;
   do {
      seq = read_seqbegin(&xtime_lock);
      ret = jiffies_64;
   } while (read_seqretry(&xtime_lock, seq));
   return ret;
}

write_seqlock()ライターは、 とを使用して重要な領域を保護しwrite_sequnlock()ます。

2.6 カーネルでは、 Read-Copy Update (RCU)と呼ばれる別のメカニズムが導入されました。これにより、リーダーがライターよりもはるかに多い場合にパフォーマンスが向上します。基本的な考え方は、リーダー スレッドはロックせずに実行できるということです。ライター スレッドはより複雑です。これらは、データ構造のコピーに対して更新操作を実行し、リーダーに表示されるポインターを置き換えます。元のコピーは、進行中のすべての読み取り操作が確実に完了するように、すべての CPU で次にコンテキストが切り替わるまで維持されます。RCU の使用は、これまでに説明したプリミティブを使用するよりも複雑であり、それが仕事に適したツールであることが確実な場合にのみ使用する必要があることに注意してください。RCU データ構造とインターフェイス関数は で定義されていinclude/linux/rcupdate.hます。には十分なドキュメントがあります Documentation/RCU/*

RCU の使用例については、 を参照してfs/dcache.cください。Linux では、各ファイルは、ディレクトリ エントリ情報 (dentry と呼ばれる構造に格納)、メタデータ情報 (inode に格納)、および実際のデータ (データ ブロックに格納) に関連付けられています。ファイルを操作するたびに、ファイル パス内のコンポーネントが解析され、対応する dentry が取得されます。将来の操作を高速化するために、dentry は dcache と呼ばれるデータ構造にキャッシュされたままになります。いつでも、dcache ルックアップの数は dcache 更新よりもはるかに多いため、dcache への参照は RCU プリミティブを使用して保護されます。

于 2009-11-09T19:20:31.167 に答える
3

これは、RCUが処理するように設計された種類の使用例ではありませんか?その使用法についての良い記事については、http://lwn.net/Articles/262464/を参照してください。

于 2009-06-01T16:00:14.783 に答える
0

ロックを保持している間に行う作業が小さい場合は、リーダーライターではない通常のミューテックスを試すことができます。より効率的です。

于 2009-05-31T21:30:50.293 に答える