目次
はじめに
マルチスレッドプログラミングでは、特定のスレッドの実行を、意図的に一定時間だけ**一時停止(スリープ)**させたい場面がよくあります。例えば、定期的に処理を実行したり、他のスレッドとのタイミングを調整したりするケースです。
C++の標準ライブラリには、このスレッドのスリープを実現するための2つの関数が用意されています。
sleep_for()
: 「今から〇秒間」のように、相対的な時間を指定してスリープさせる。sleep_until()
: 「〇時〇分〇秒になったら起きる」のように、絶対的な時刻を指定してスリープさせる。
この記事では、<thread>
と <chrono>
ライブラリを使い、これら2つの関数でスレッドを一時停止させる方法を解説します。
1. sleep_for()
: 相対的な時間だけスリープする
sleep_for()
は、引数で指定された時間だけ、現在のスレッドの実行を中断します。
サンプルコード
#include <iostream>
#include <thread>
#include <chrono> // 時間を扱うために必要
using namespace std;
void task_relative_sleep() {
cout << "タスク開始 (3秒後に終了します)" << endl;
// 1. スリープさせる時間を定義
chrono::seconds duration(3);
// 2. 現在のスレッドを指定した時間だけスリープさせる
this_thread::sleep_for(duration);
cout << "タスク終了" << endl;
}
int main() {
thread worker(task_relative_sleep);
worker.join();
return 0;
}
解説:
chrono::seconds duration(3);
:<chrono>
ライブラリを使って、「3秒」という時間を表現するduration
オブジェクトを作成しています。chrono::milliseconds(500)
のように、ミリ秒単位での指定も可能です。this_thread::sleep_for(duration);
:this_thread
は現在のスレッド自身を指します。sleep_for
にduration
を渡すことで、「このスレッドを3秒間停止させなさい」と命令しています。
2. sleep_until()
: 絶対的な時刻までスリープする
sleep_until()
は、引数で指定された時刻になるまで、現在のスレッドの実行を中断します。
サンプルコード
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
void task_absolute_sleep() {
cout << "タスク開始" << endl;
// 1. 起き上がる時刻を定義 (現在の時刻の3秒後)
auto wake_up_time = chrono::steady_clock::now() + chrono::seconds(3);
// 2. 指定した時刻になるまでスリープ
this_thread::sleep_until(wake_up_time);
cout << "タスク終了 (開始から約3秒後)" << endl;
}
int main() {
thread worker(task_absolute_sleep);
worker.join();
return 0;
}
解説:
auto wake_up_time = chrono::steady_clock::now() + chrono::seconds(3);
:chrono::steady_clock::now()
で現在の時刻を取得し、それに「3秒」という時間を足すことで、3秒後の未来の時刻を計算しています。this_thread::sleep_until(wake_up_time);
:sleep_until
に、計算した未来の時刻wake_up_time
を渡すことで、「この時刻になるまでスリープしなさい」と命令しています。
まとめ
今回は、C++でスレッドの実行を一時停止させる2つの方法を解説しました。
this_thread::sleep_for()
: 相対的な時間(例: 200ミリ秒間)を指定してスリープさせる場合に使う。this_thread::sleep_until()
: 絶対的な時刻(例: 次の定時まで)を指定してスリープさせる場合に使う。
ほとんどの場合、sleep_for
の方が直感的で使いやすいですが、厳密な時刻に同期させたい処理では sleep_until
が役立ちます。これらの関数を適切に使うことで、スレッド間の同期や、タスクの実行タイミングを精密に制御することが可能になります。