2016-05-19 6 views
1

std::condition_variableとbool conditionを介してワーカースレッドの実行をトリガーしようとしています。作業者は通知を待ち、conditionが真であれば作業を開始します。作業後はconditionがfalseに設定されます。さらに、同期するためのミューテックスがあります。他のスレッドでスレッド内に割り当てられていないものがあります

メインスレッドでは、ループがconditionがfalseであるかどうかをチェックし、そうである場合はconditionがtrueに設定され、condition_variableに通知されます。

出力が「スパム」作業とを目が覚めただろうと、私は期待するこのコードを実行し、何とかthread_function()conditionへの割り当てがメインに表示されていないので、それは、一度だけ実行されますスレッド/はワーカースレッド内で失われます。代入の後、デバッガでそれを調べると、代入の後ではfalseになりますが、メインスレッドのifが評価されると、それは再び真です。

何か不足していますか?

私はこれをVS2013とVS2012で試しましたが、boolstd::atomic_boolに置き換えようとしましたが、それでも役に立たなかったです。

#include <thread> 
#include <mutex> 
#include <condition_variable> 
#include <iostream> 
#include <atomic> 

bool condition; 
std::mutex condition_mutex; 
std::condition_variable cv; 

void thread_function() { 
    while (true) { 
     std::unique_lock<std::mutex> lock(condition_mutex); 
     cv.wait(lock); 
     std::cout << "woke up\n"; 
     if (condition) { 
      // do stuff 
      std::cout << "thread working\n"; 
      condition = false; 
      std::cout << "thread: " << (condition ? "true" : "false") << "\n"; 
     } 
    } 
} 

int main() { 
    condition = false; 
    std::thread t(&thread_function); 

    while (true) { 
     std::unique_lock<std::mutex> lock(condition_mutex); 
//  std::cout << "main: " << (condition ? "true" : "false") << "\n"; 
     if (!condition) { 
      condition = true; 
      cv.notify_one(); 
     } 
    }  
    return 0; 
} 

答えて

1

あなたは、whileループの外にロックを配置する必要があります。

void thread_function() { 
    std::unique_lock<std::mutex> lock(condition_mutex); 
    while (true) { 
     cv.wait(lock); 
     std::cout << "woke up\n"; 
     if (condition) { 
      // do stuff 
      std::cout << "thread working\n"; 
      condition = false; 
      std::cout << "thread: " << (condition ? "true" : "false") << "\n"; 
     } 
    } 
} 

スレッド関数ループを再入力するときに、非常にすぐにロックを失います。これにより、メインスレッドは誰も待機していない間にcv.notify_one()を呼び出すことができます。

+0

cv.wait(ロック)で "偽の"起床が発生することがあります。つまり、notify_one()やnotify_all()によって引き起こされない起床です。 cv.wait()はmutexを待つのではなく、notify_one()またはnotify_all()を待ちます。スレッドセーフな内部動作と条件変数のチェックのためだけにmutexを使用します。とにかく、プログラム全体は意味をなさないが、それはどんな一時停止もせずにお互いに依存する2つの無限ループを持ち、いずれのループの内部でも行う。私は、これが実行されているCPUコアが実行中に100%であると推測します。 – BJovke

+0

@BJovkeここであなたは絶対に正しいです、条件は、待機の前または後にチェックされないので、問題ありません。 –

+0

@Alan Strokes待機後に状態がチェックされるため、偽の起床では問題は発生しません。 –

1

待つ標準的な方法は、あなたの問題を解決するだろう条件を、テストが含ま:

while (!condition) cv.wait(lock); 

http://en.cppreference.com/w/cpp/thread/condition_variable/waitを参照してください。

+0

間違っていますが、それはcv.wait(ロック、[] {戻り条件;})でなければなりません。 。このような条件をテストするときは、条件が原子変数でない限りスレッドセーフではありません。 – BJovke

+0

@BJovkeナンセンス。 2つはまったく同等です(リンクを参照)。ロックは、待機が進行中である場合を除いて、両方の場合に保持されます。 –

+0

あなたは投稿したリンクをチェックします: "waitは、条件変数が通知されるか、**偽の**起床が発生するまで、現在のスレッドをブロックさせます"。これは、起床がnotify_one()またはnotify_all()なしで発生する可能性があることを意味します。これをチェックしてください:[https://en.wikipedia.org/wiki/Spurious_wakeup](https://en.wikipedia.org/wiki/Spurious_wakeup)。投稿したリンクには、condition_variableが内部的にどのように動作しているかが示されています。これまでは、提供されたmutexのロックがすでに取得されていることを前提としています。つまり、スレッドセーフであるかどうかです。 – BJovke

関連する問題