c++ jthread
自動join
std::threadでは、スレッドが終了する前にthreadオブジェクトが破棄されるとstd::terminate()が呼ばれる。そのため、join()を呼んで、スレッドの終了を待つ必要がある。 (スレッドの管理が必要ないのであれば、detach()でもよい)
TEST(thread, cpp20) { using namespace::std::literals; int x{0}; std::thread t([&]() { std::cout << "thread start" << std::endl; while(x < 10){ std::this_thread::sleep_for(0.5s); std::cout << "x:" << x++ << std::endl; } std::cout << "thread exit" << std::endl; }); std::this_thread::sleep_for(2s); t.join(); // <<<<<<<< スレッドの終了を待つ }
std::jthreadでは、jthreadオブジェクトが破棄される際にjoin()が自動的に呼ばれるので、明示的にjoin()を呼ぶ必要はない。
TEST(jthread, cpp20) { using namespace::std::literals; int x{0}; std::jthread t([&]() { std::cout << "thread start" << std::endl; while(x < 10){ std::this_thread::sleep_for(0.5s); std::cout << "x:" << x++ << std::endl; } std::cout << "thread exit" << std::endl; }); std::this_thread::sleep_for(2s); // スレッドが終了するまで、自動的に待つ }
スレッドのキャンセル
request_stop()の呼び出しで、スレッドをキャンセルできる。
TEST(jthread_cancel, cpp20) { using namespace::std::literals; int x = 0, y = 0; std::jthread t([&](std::stop_token token) { std::cout << "thread start" << std::endl; while(x < 10){ // 停止要求があれば終了 if(token.stop_requested()){ std::cout << "stop requested" << std::endl; break; } std::this_thread::sleep_for(0.5s); std::cout << "x:" << x++ << std::endl; } std::cout << "thread exit" << std::endl; }); // スレッドに対する停止要求で呼び出されるコールバック std::stop_callback sc { t.get_stop_token(), [&] { std::cout << "stop_callback" << std::endl; y++; }}; ASSERT_EQ(x , 0); std::this_thread::sleep_for(2s); t.request_stop(); // スレッド停止要求 ASSERT_EQ(y , 1); }
std::latchによるスレッド同期
std::latchを使って、値が0になるまで待つ。
TEST(latch, cpp20) { using namespace::std::literals; const int num_threads = 5; std::latch l(num_threads); std::vector<std::jthread> threads; // 5つのスレッドを起動 for(int i = 0 ; i < num_threads ; i++) threads.push_back(std::jthread([i, &l](){ std::cout << "thread " << i << " start" << std::endl; std::this_thread::sleep_for(i * 1s); std::cout << "thread " << i << " exit" << std::endl; l.count_down(); // 1つ減らす })); l.wait(); // latchが0になるまで待つ std::cout << "all threads exit" << std::endl; }
std::counter_semaphoreによる同時実行数の制限
std::counter_semaphoreを使って、特定の処理を同時に実行できるスレッドの数を制限できる。
TEST(semaphore, cpp20) { using namespace::std::literals; const int num_threads = 10; const int num_semaphre = 3; std::counting_semaphore semaphore(num_semaphre); std::vector<std::jthread> threads; std::atomic<int> counter; // 10のスレッドを起動 for(int i = 0 ; i < num_threads ; i++) threads.push_back(std::jthread([i, num_semaphre, &semaphore, &counter](){ semaphore.acquire(); // 空きを待つ std::cout << "counter=" << ++counter << std::endl; std::cout << "thread " << i << " acquired" << std::endl; ASSERT_LE(counter, num_semaphre); // 3以下のはず std::this_thread::sleep_for(i * 1s); counter--; std::cout << "thread " << i << " exit" << std::endl; semaphore.release(); // セマフォ開放 })); }