pthread条件変数の深い解析

2557 ワード

条件変数を用いたイベント待機器の正確さと誤りを実現する方法linux pthread条件変数に基づいて実現された8種類のWaiter classesに言及し,いくつかの誤り実現の誤り点を解析した.本論文では,いくつかの正確に実現されたプログラム挙動をさらに解析し,Linux pthread条件変数の理解を深める.
次にsingle waiterに使用できるWaiterClassの正確な実装を示す.
class Waiter : private WaiterBase
{
 public:
  void wait()
  {
    CHECK_SUCCESS(pthread_mutex_lock(&mutex_));
    while (!signaled_)
    {
      CHECK_SUCCESS(pthread_cond_wait(&cond_, &mutex_));
    }
    CHECK_SUCCESS(pthread_mutex_unlock(&mutex_));
  }

  void signal()
  {
    CHECK_SUCCESS(pthread_mutex_lock(&mutex_));    // 0
    signaled_ = true;                              // 1
    CHECK_SUCCESS(pthread_mutex_unlock(&mutex_));  // 2
    CHECK_SUCCESS(pthread_cond_signal(&cond_));    // 3
  }

 private:
  bool signaled_ = false;
};

正しいWaiter Classを実現するには、wait()関数の命令順序を1で知る必要があります.しかし、signal()関数には、コード行1,2,3がWaiter Classが正しいように、いくつかの異なる順序で組み合わせられるいくつかの異なる実装があり得る.これらのいくつかの組合せは、1が与えるいくつかの正確な実装を含む.
まず、コード行1,2,3に対して可能なすべての配列形式を与え、次に、それが正しいかどうかを一つ一つ説明する.a. 1-2-3b. 1-3-2c. 2-1-3d. 2-3-1e. 3-1-2f. 3-2-1
以上の6つの実装の誤りを分析するには、pthread_を理解しておく必要があります.cond_waitとpthread_cond_Signalの内部プロセス.
待機信号のスレッドをAとし,信号を送信するスレッドをBとする.
スレッドA,pthread_cond_wait()の内部には、次のプロセスがあります.
  • waiterをcondに追加する_wseqキュー(G 1 G 2の2つのグループに分かれている)
  • mutex
  • を解放
  • スピン待ち、チェック_g_Signals、スピン回数終了、futex_へwait,スリープ
  • スレッドB,pthread_cond_Signal()には、次のプロセスが含まれます.
  • チェックcond_wseqは、待機者がいなければ直接戻ります.
  • に待機者がいて、グループを切り替える必要があるかどうかをチェックし(例えば、waitが最初に呼び出された後G 1が空で、G 2に待機者が1人いる場合、signalが最初に呼び出された後G 2をG 1に切り替える必要がある)、インクリメント_g_Signals,減算_g_size(起動していないwaitersの数)、futex_を呼び出します.wake.

  • Signalは、G 1のすべてのwaitersが起動するまで、G 1グループのwaitersを呼び覚ます.このプロセスに新たに到着したwaiterがある場合、G 2グループに格納される(その後到着したwaiterもG 2に格納される).G 2グループは、次回のsignal呼び出し時にG 1グループに移行するため、signalは常にG 1グループのwaitersのみを起動します.(参考)
    以上の細部があれば、問題の結論を簡単に出すことができます.
  • は、まずeおよびfを排除しなければならない.efはロックを取得してすぐにロックを解除し、1と2はロックによって保護されず、1,2の実行タイミングはwait()関数の各文zhi'jianに任意に挿入することができ、文2の信号が
  • を失う可能性が高い.
  • dもエラーです.スレッドAの餓死を招くタイミング:2信号、スレッドAを起動し、3ロックを解放し、Aはロックを獲得し、ブール値を判断し、条件は真であり、再び待機に入り、
  • 休眠した.
  • acが正しいです.発信時にブール値を変更したかどうかにかかわらず、起動されたAスレッドは常にmutexを得ることができず、3がロックを解除するまでfutex_wakeはスレッドAに通知して、Aはやっとロックを手に入れることができて、pthread_からcond_waitは戻って、下に実行を続けます.このとき、ブール値は変更され、条件テストは偽で、ループから飛び出して、実行を続けます.実際,コンパイラ乱順とCPU乱順のため,acが動作する可能性のある順序は同じである.
  • bも正しい.Bスレッドはブール変数を修正した後にロックを解放し、この時スレッドAは依然として休眠状態にあり、発生したすべてを知らない.Bが信号を送ってAを起動したときだけ、Aはこのすべてを見ることができ、ロックを成功に獲得し、さらに下へ実行し続ける.

  • まとめると,ブール値の修正がロックを解放する操作である限り,その正確性が保証されることが分かった.