4

優先度の低いライターをサポートするリーダー/ライターロックを見つけようとしています(または実装しようとしています)が、既存のソリューションの調査に失敗しました。

優先度の低いライターとは、次の読者や通常のライターに「一列に並ぶ」という意味です。

リーダーが絶えず流れている場合は確かに飢餓につながりますが、これは時限ロックのバリエーション(「時限低優先度ライターロックを試してからタイムアウト時に通常のロックに切り替える」)またはリーダーの方法を変更することで解決できます。が発行されます(おそらく、短いウィンドウで定期的に読み取りを停止します)。

これらの線に沿って何かを説明している文献があれば、私はそれを見つけていません。

通常のロックを利用する既知の(正しい!)解決策がある場合は、説明をいただければ幸いです。

4

3 に答える 3

3

私はあなたの提案のように100%何も知りませんが、近くにあるいくつかの既存のインターフェースがあります:

pthread_rwlock_trywrlock()多くの既存のr/wロックAPIには、 UN*Xシステムのように「trylock」インターフェースがあります。これらは待機なしであり、誰もそれを所有していないか、すでにそれを待っていない場合にのみ、ロックを取得します。

通常、この回転をロックに使用するか、試行コードを人為的に遅らせます(バックオフ)。つまり、次のようなコードがあります。

for (count = 0; count < MAX_SPINS && (locked = trywrlock(lock)); count++);
if (locked) {
    delay(some_backoff);
    wrlock(lock);         /* or try spinning loop above again ? */
}

残念ながら、これはあなたが求めているものではありません。ロックは遅くても問題なく取得されますが、低優先度のライターはCPUでスピンするか、(おそらく不要な)バックオフのために遅延してロックを取得します。

Solarisカーネルにはrw_tryupgrade(9f)、現在のスレッドがロック上の唯一のリーダーであり、ライターが待機していないかどうかをテストするために使用できるインターフェイスがあります。その場合は、ロックを排他的/書き込みにアップグレードします。つまり、次のようにコーディングします。

if (!rw_tryenter(lock, RW_WRITER)) {
    rw_enter(lock, RW_READER);    /* this might wait for a writer */
    if (!rw_tryupgrade(lock)) {   /* this fails if >1 reader / writer waiting */
        /* do what you must to if you couldn't get in immediately */
    }
}

これはあなたが求めているものに少し近いですが、それでもまったく同じではありません-失敗した場合は、リードロックをドロップし、場合によってはバックオフ(待機)し、リードロックを再取得して、アップグレードを試みる必要があります。そのプロセスもまた回転に相当します。

また、多くのUNIXシステムは、少なくとも実際には、スケジューリングの優先順位に従ってウェイターのウェイクアップを実行します。wrlock()したがって、通常の待機中の呼び出しを試みる前に、スレッドの優先度を(必然的に、人為的に)最低にする必要があります。スケジューラがどのように機能するかによって、スレッドが待機している間に他の人が同じ書き込みロックを必要とする場合は、その前にそれを取得します。マルチプロセッサ/コアシステムでは、必ずしも保証されているわけではありませんが...

最後に、SymbianOS(Symbian ^ 3バージョン)には、RRWlockライターよりもリーダーを優先するように作成できるクラスがあります。これにより、リーダーが待機中/着信している場合に、ライターを意図的に飢えさせることができます。特定のロックだけでなく、特定のロックのすべてのライターに影響します。

恐れ入りますが、2つのライターウェイクアップキューを使用して、独自の優先ロックを作成する必要があります。

于 2011-02-22T18:17:02.263 に答える
1

ここで見ているのは、リーダーとライターの間の優先順位付けであり、優先度の低いライターは常に優先度の高いリーダーに最初のチャンスを与えます。これは明らかに、その寛大さのために、優先度の低いライターにとって飢餓につながる可能性があります。

これは、2つの異なるレベルで達成できます。1。アプリケーション側から:通常、ミューテックスにはバイアスがかからないため、これは通常のアプローチです。スレッドがロックを争う前に、アプリケーションロジック自体が優先度の高いスレッドを決定し、そのスレッドがロックに進むことを許可する必要があります。これは通常、アプリケーション固有になります。

->タスク実行者アプローチ:実行者スレッドは、優先度に基づいてのみ使用可能なタスクを実行します。実行者レベルで優先度ベースの実行を解決しますが、同じ問題がそのレベルより上にポップアップします。これは、FIFOベースの長いミューテックス実装として機能します。これはまた、飢餓の問題を解決する必要があります。

  1. 優先度を理解し、優先度の高いスレッドをロックできるようにする、バイアスのかかったロックメカニズムを記述します。これはまた、「飢餓がない」ことを保証する必要があります。即興バージョンのミューテックスを実装することが可能です。
于 2018-07-08T08:22:28.370 に答える
0

私の頭のてっぺんから、あなたはこのようなものが欲しいでしょう:

class PriorityRWLock
{ 
  int                rwcount;
  mutex              mtx;
  condition_variable cv;
  priority_queue<writer_info> writers;
};

...およびPriorityRWLock::acquire_write_lock()は次のようになります。

lock_guard raii(mtx);

do {
if ( rwcount==0 ) // == no read or write locks
{
  if ( writers.top().thread == thread::self() )
  {  rwcount = -1; writers.pop_front(); break; } // == exclusive write access
  else 
  { 
     // wake up the waiting thread(s) and sleep
     writers.push( writer_info(thread::self(),priority) ); 
     cv.notify_all();
     cv.wait(mtx); 
  }
}
else
{ cv.wait(mtx); }  // sleep
} while ( true );

...またはそれに近いもの。

過度に効率的になることはありません。rwcountをatomic_intなどに格納することをお勧めしますが、condition_variableが必要なためそれができません。

断続的にwait()が必要になる可能性があるため、時限ロックには注意が必要です。try_write_lock()は実行可能である必要があります。

于 2011-02-22T18:30:47.653 に答える