2016-07-21 13 views
1

pthread条件変数を使用してスレッド同期に問題が発生しています。私はいくつかの値を抽出するメッセージと抽出された値を使用していくつかの変数をインクリメントする別のスレッドを解析する1つのスレッドを持っています。 これらの2つのスレッドを同期するためにpthread条件変数を使用しました。 最初のスレッドは、以下のスニペットのようになります。pthread条件変数とのスレッド同期

if(parse_ok){ 
    pthread_mutex_lock(&q_mutex); 
    q = extract_value(); 
    q_changed = true; 
    printf("...awake\n"); 
    pthread_cond_signal(&q_cond_var); 
    pthread_mutex_unlock(&q_mutex); 
} 

ワーカースレッドは以下のスニペットのようになります。

while(true){ 
    pthread_mutex_lock(&q_mutex);        
    if(!q_changed){ 
    std::cout<<"waiting..!"<<std::endl; 
    pthread_cond_wait(&q_cond_var, &q_mutex); 
    }              
    if(q_changed){ 
    q_changed = false; 
    _actual_q += q; 
    _total_q += q; 
    _quant_q += q/_fixed_quantity; 
    } 
    pthread_mutex_unlock(&q_mutex); 
}//END of while TRUE          

このコードは正しくほとんどの時間を動作します。 スリープ中のスレッドがいくつかの目覚めをスキップするという、多くのメッセージを順番に受け取ると、時々起こります。作業スレッドが作業を完了するまで、受信スレッドをブロックするためにセマフォーが必要な場合がありますか?どうやって? ありがとうございます。

A)のprintfとCOUTはスレッドセーフではありません、ので、それらの出力は待ちの実際の順序を反映し、コードに目覚めていない可能性があります

+0

q_changed *揮発性にすることをお勧めします:

if(parse_ok){ pthread_mutex_lock(&q_mutex); while (q_changed) // Always wait in in loop pthread_cond_wait(&q_cond_var, &q_mutex); q = extract_value(); q_changed = true; pthread_cond_signal(&q_cond_var); pthread_mutex_unlock(&q_mutex); } 

をそして、あなたの第二、これにワーカースレッドを変更します。 – JimmyB

答えて

1

あなたのコードが書かれている方法は、第二ワーカースレッドが毎回最初のスレッド信号も新しい入力を処理する一切保証ありません。ただし、これが発生することを確実にするために、変数q_changedの使用を拡張することができます。

これまであなたの最初のスレッドに変更し

:*

while(true){ 
    pthread_mutex_lock(&q_mutex); 
    while(!q_changed) // Always wait in a loop 
     pthread_cond_wait(&q_cond_var, &q_mutex); 
    q_changed = false; 
    _actual_q += q; 
    _total_q += q; 
    _quant_q += q/_fixed_quantity; 
    pthread_cond_signal(&q_cond_var);  
    pthread_mutex_unlock(&q_mutex); 
} 
+0

あなたのソリューションは完璧に動作します。 –

2

は、潜在的に、ここであなたをかむいくつかあります。

b)スプリアスウェイクアップは、コード内で効率的に処理されません。私は、if( !q_changed)while (!q_changed)に変更して、条件変数が覚醒したときに再送するのにかかる時間を最小限に抑えるようにします(これにより、最後のif (q_changed)条件ブロックを削除することもできます)。

EDIT(@EOFなどのコメントに基づいています):最新のC++/C実装を使用している場合(pthreadを使用しているからではないと思われます)、b)は問題です。この場合のレースは、待機中のスレッドが目を覚ましてからミューテックスのロックを解除できることです。その間、シグナリングスレッドはロックとシグナルを取得します。あなたがその状態を待っていなかったので、あなたはその信号を得ていませんでした。しかし、それは問題ではないことに注意してください - あなたはまだデータを処理しています - この場合、あなたは「待機中」のメッセージを出力しませんでした。

+0

C11ドラフト標準n1570:* 7.21.2ストリーム7各ストリームには関連するロックがあり、複数の スレッドがストリームにアクセスし、複数のスレッドによってストリーム操作のインターリーブを制限する場合のデータ競合を防ぎます。一度に1つのスレッドだけがこのロックを保持できます。ロックは リエントラントです:ある時点で1つのスレッドがロックを複数回保持することがあります。* 'printf()' *はスレッドセーフです。 – EOF

+0

@EOF C++ 11とC++ 14には* C99 *が組み込まれていて、C++ 17には* C11 *が組み込まれたCバージョンであることを忘れています。したがって、C11に基づくルールは無関係です。 (完全性のために、C++ 98/03はC89を組み込んだ)。 –

+0

@JesperJuhl 1)質問にはCとC++のタグが付いています。2)その場合、C関数の* none *はC++でスレッドセーフです。なぜならC11より前のCでは*スレッドがないからです。 – EOF

関連する問題