スポンサーリンク

C++ std::condition_variableについて

スレッドプールのコードの中でわからなかったcondition_variableについて調べた。

条件変数と訳される。wait()で待機状態にしたスレッドに対して、別のスレッドからnotify_all()で通知を送ると待機していたスレッドが動き出す。

 

condition_variable使用例1 (不完全版)

コード

#pragma warning(disable:4996)

#include <iostream>

#include <functional>
#include <thread>

#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;

void func1() {


  for (size_t i = 0; i < 10;i++) {
    _sleep(10);
    printf("func1 # %d\n", i);

    if (i == 5) {
      printf("*** func1 から通知を送る *** \n");
      cv.notify_all();
    }
  }

}

      
      
      
void func2() {

  printf("待機開始\n");
  std::unique_lock<std::mutex> ul(mtx);
  cv.wait(ul);
  printf("通知が来たので func2 スレッド再開\n");

  for (size_t i = 0; i < 10; i++) {
    _sleep(10);
    printf("func2 : %d\n", i);
  }
  
}

int
main() { std::thread th1(func1); std::thread th2(func2); th1.join(); th2.join(); std::cout << "Hello World!\n"; }

実行結果

待機開始
func1 # 0
func1 # 1
func1 # 2
func1 # 3
func1 # 4
func1 # 5

*** func1 から通知を送る ***
通知が来たので func2 スレッド再開
func2 : 0
func1 # 6
func2 : 1
func1 # 7
func1 # 8

func2 : 2
func2 : 3

func1 # 9
func2 : 4
func2 : 5
func2 : 6
func2 : 7
func2 : 8
func2 : 9

Hello World!

condition_variable使用例2 spurious wakeup対応

condition_variableは、.wait()の場所で、notify_all()などで通知が来るまで待機するのだが、「たまに、なぜか知らないが、どういうわけか通知が来ていないのに待機が解除されてしまいスレッドが走り出す」という現象が起こるらしい。これをspurious wakeupといい、condition_variableを使う場合、この現象への対応をしておかなければならないという。

コード ステート変数使用版

ステート変数notifyを追加し、この変数がtrueの時だけwaitを解除する。

#pragma warning(disable:4996)

#include <iostream>

#include <functional>
#include <thread>

#include <mutex>
#include <condition_variable>

bool notify = false; // Spurious Wakeup考慮 ステート変数
std::mutex mtx;
std::condition_variable cv;

void func1() {


  for (size_t i = 0; i < 10;i++) {
    _sleep(10);
    printf("func1 # %d\n", i);

    if (i == 5) {
      printf("*** func1 から通知を送る *** \n");
      notify = true;// notify_allするときにしかnotifyがtrueになることはない
      cv.notify_all();
    }
  }

}


void func2() {

  printf("待機開始\n");

  std::unique_lock<std::mutex> ul(mtx);
  cv.wait(ul, [&]{return notify; });// notifyがtrueの時だけ待機解除

  printf("通知が来たので func2 スレッド再開\n");

  for (size_t i = 0; i < 10; i++) {
    _sleep(10);
    printf("func2 : %d\n", i);
  }
  
}


int main()
{

  std::thread th1(func1);
  std::thread th2(func2);

  th1.join();
  th2.join();

  std::cout << "Hello World!\n";
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: