10

pthread条件変数のコードを理解するために、私は独自のバージョンを作成しました。正しく見えますか?私はそれをプログラムで使用していますが、動作は驚くほど高速です。元々、プログラムは約2.5秒かかりますが、私のバージョンの条件変数では0.8秒しかかからず、プログラムの出力も正しいです。ただし、私の実装が正しいかどうかはわかりません。

struct cond_node_t
{
    sem_t s;
    cond_node_t * next;
};

struct cond_t
{
    cond_node_t * q;                // Linked List
    pthread_mutex_t qm;                 // Lock for the Linked List
};

int my_pthread_cond_init( cond_t * cond )
{
    cond->q = NULL;
    pthread_mutex_init( &(cond->qm), NULL );
}

int my_pthread_cond_wait( cond_t* cond, pthread_mutex_t* mutex )
{
    cond_node_t * self;

    pthread_mutex_lock(&(cond->qm));
    self = (cond_node_t*)calloc( 1, sizeof(cond_node_t) );
    self->next = cond->q;
    cond->q = self;
    sem_init( &self->s, 0, 0 );
    pthread_mutex_unlock(&(cond->qm));

    pthread_mutex_unlock(mutex);
    sem_wait( &self->s );
    free( self ); // Free the node
    pthread_mutex_lock(mutex);
}

int my_pthread_cond_signal( cond_t * cond )
{
    pthread_mutex_lock(&(cond->qm));
    if (cond->q != NULL) 
    {
        sem_post(&(cond->q->s));
        cond->q = cond->q->next;
    }
    pthread_mutex_unlock(&(cond->qm));
}

int my_pthread_cond_broadcast( cond_t * cond )
{
    pthread_mutex_lock(&(cond->qm));
    while ( cond->q != NULL) 
    {
        sem_post( &(cond->q->s) );
        cond->q = cond->q->next;
    }
    pthread_mutex_unlock(&(cond->qm));
}
4

3 に答える 3

5

欠落している戻り値のチェックとは別に、修正できるはずの問題がいくつかあります。

  • sem_destroyは呼び出されません。
  • cond_node_tターゲットスレッドをウェイクアップした後、シグナル/ブロードキャストタッチが発生し、解放後の使用につながる可能性があります。

さらなるコメント:

  • 省略された破棄操作では、他の操作を変更する必要がある場合があるため、POSIXが安全であると判断した場合は、条件変数を破棄しても安全です。破棄をサポートしないか、呼び出されるタイミングに強い制限を課すと、作業が簡素化されます。
  • 本番実装はスレッドキャンセルを処理します。
  • 待機を取り消すと(スレッドのキャンセルやpthread_cond_timedwaitタイムアウトに必要な場合など)、問題が発生する可能性があります。
  • 実装はユーザーランドでスレッドをキューに入れます。これは、パフォーマンス上の理由から一部の本番実装で行われます。理由はよくわかりません。
  • 実装は常にスレッドをLIFOの順序でキューに入れます。これは多くの場合(キャッシュ効果などのために)高速ですが、枯渇につながる可能性があります。本番実装では、飢餓を回避するためにFIFOオーダーを使用する場合があります。
于 2012-06-12T23:14:31.940 に答える
4

基本的にあなたの戦略は大丈夫に見えますが、あなたには1つの大きな危険、いくつかの未定義の振る舞い、そしてちょっとした選択があります:

  • POSIX関数の戻り値を検査していません。特にsem_wait中断可能であるため、高負荷または不運の下でスレッドが誤ってウェイクアップされます。あなたはそれらすべてを注意深く捕らえる必要があるでしょう
  • どの関数も値を返しません。関数の一部のユーザーがいつか戻り値を使用することを決定した場合、これは未定義の動作です。条件関数が返すことが許可されているエラーコードを注意深く分析し、それを実行します。
  • mallocまたはのリターンをキャストしないでくださいcalloc

編集:malloc実際には、 /はまったく必要ありませんfree。ローカル変数も同様に機能します。

于 2012-06-12T16:50:17.093 に答える
3

この要件を尊重していないようです。

これらの関数は、ミューテックスをアトミックに解放し、呼び出し元のスレッドが条件変数condでブロックするようにします。ここでアトミックとは、「アトミックに、別のスレッドによるミューテックスへのアクセス、次に条件変数へのアクセスに関して」を意味します。つまり、ブロックしようとしているスレッドがミューテックスを解放した後に別のスレッドがミューテックスを取得できる場合、そのスレッドでのpthread_cond_broadcast()またはpthread_cond_signal()の後続の呼び出しは、約-の後に発行されたかのように動作します。 to-blockスレッドがブロックされました。

ロックを解除してから待ちます。別のスレッドは、これらの操作の間に多くのことを実行できます。

PSこの段落を正しく解釈しているかどうかはわかりませんが、エラーを指摘してください。

于 2012-06-12T17:55:20.083 に答える