特定のシナリオに最適な Linux カーネル ロック メカニズムは何ですか?

これは、あなたが探しているかもしれない 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 プリミティブを使用して保護されます。


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