C++で学ぶ!ミリ秒単位での時間取得方法8選 – Japanシーモア

C++で学ぶ!ミリ秒単位での時間取得方法8選

C++で時間取得をミリ秒単位行う方法を解説するイメージC++
この記事は約15分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

このサービスは複数のSSPによる協力の下、運営されています。

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

C++はプログラミング言語として広く利用されていますが、その機能の中でも時間をミリ秒単位で取得する方法は非常に重要です。

この記事では、C++を用いてミリ秒単位で正確な時間を取得する方法を初心者から上級者までわかりやすく解説します。

時間を正確に測定することは、アプリケーションのパフォーマンス改善、効率的なリソース管理、ユーザー体験の向上など、多くの分野で重要な役割を果たします。

●C++と時間取得の基礎

C++で時間を扱う際には、いくつかの異なる方法やライブラリがあります。

標準ライブラリには時間を扱うための多くの関数が含まれていますが、これらの関数は時に異なる精度や形式を持っています。

C++11以降では、<chrono>ライブラリが導入され、より精確で読みやすい時間処理が可能になりました。

時間の測定には、大きく分けてシステム時間とプロセス時間があり、これらはそれぞれ異なる目的で使用されます。

システム時間は実際の壁掛け時計の時間に相当し、プロセス時間はプログラムが実行されるCPUの時間を表します。

○C++における時間の取り扱い

C++で時間を取り扱う際、最も一般的な方法は<chrono>ライブラリを使用することです。

このライブラリは時間の点や期間を表現するための一連のクラスを提供します。

例えば、std::chrono::system_clockはシステムの現在時刻を取得するために使用され、std::chrono::steady_clockは連続した時間を計測するのに適しています。

また、時間の期間を表すためには、std::chrono::durationクラスが使われます。

○ミリ秒単位とは何か

ミリ秒単位の時間測定は、1秒の1000分の1に相当します。

これは、高精度のタイミングが要求されるアプリケーションや、ユーザーのインタラクションを正確に追跡する必要がある場面で特に重要になります。

例えば、オンラインゲームやリアルタイムシステムでは、ミリ秒単位での時間計測が必須です。

C++の<chrono>ライブラリを使用すると、ミリ秒単位の時間を簡単に取得し、処理することが可能になります。

○基本的な時間関数の紹介

C++で時間を取得する基本的な関数には、clock()time()があります。

これらはC言語から継承された関数で、シンプルですが限定的な機能しか提供しません。

clock()関数はプログラムのプロセス時間を測定し、time()関数はシステムの現在時刻を秒単位で返します。

これらの関数は、高精度やミリ秒単位の時間測定には向いていないため、より精確な時間計測には<chrono>ライブラリが推奨されます。

<chrono>ライブラリでは、様々な時間単位を扱うことができ、時間の点や期間を簡単に操作することが可能です。

●ミリ秒単位で時間を取得する方法

C++では、ミリ秒単位での時間取得は、アプリケーションの性能測定や、タイミングに敏感なプログラム開発において不可欠です。

特に、ゲーム開発やリアルタイムシステムでは、高い精度での時間計測が求められます。

ここでは、C++でミリ秒単位の時間を取得するいくつかの方法を紹介します。

○サンプルコード1:chronoライブラリを使用した時間取得

C++の<chrono>ライブラリは、時間の取得と処理を行うための強力なツールを提供します。

下記のサンプルコードは、chronoライブラリを使用して現在時刻をミリ秒単位で取得する方法を表しています。

#include <iostream>
#include <chrono>

int main() {
    auto start = std::chrono::high_resolution_clock::now();

    // ここに時間を測定したい処理を記述

    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::milli> elapsed = end - start;
    std::cout << "経過時間: " << elapsed.count() << " ms" << std::endl;

    return 0;
}

このコードでは、high_resolution_clockを使用して高精度の時間測定を行い、開始時刻と終了時刻の差をミリ秒単位で計算しています。

elapsed.count()関数は経過時間をミリ秒で返します。

○サンプルコード2:clock()関数を使用した方法

C言語由来のclock()関数も、C++で時間を計測するために利用できます。

この関数はプログラムのCPU時間を測定し、下記のサンプルコードでミリ秒単位での時間計測に使用する方法を表しています。

#include <iostream>
#include <ctime>

int main() {
    clock_t start = clock();

    // ここに時間を測定したい処理を記述

    clock_t end = clock();
    double elapsed = (double)(end - start) / CLOCKS_PER_SEC * 1000;
    std::cout << "経過時間: " << elapsed << " ms" << std::endl;

    return 0;
}

このコードは、clock()関数を使用してプロセスのCPU時間を測定し、それをミリ秒単位に変換しています。

CLOCKS_PER_SECは1秒あたりのクロック数を示し、これを使用してミリ秒単位の時間に変換しています。

○サンプルコード3:システムクロックを利用した時間取得

システムクロックを使用してミリ秒単位での時間を取得する方法もあります。

下記のサンプルコードは、gettimeofday()関数を使用して現在のシステム時刻をミリ秒で取得する方法を表しています。

#include <iostream>
#include <sys/time.h>

int main() {
    struct timeval start, end;

    gettimeofday(&start, NULL);

    // ここに時間を測定したい処理を記述

    gettimeofday(&end, NULL);
    long elapsed = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000;
    std::cout << "経過時間: " << elapsed << " ms" << std::endl;

    return 0;
}

このコードでは、gettimeofday()関数を使用してUNIXエポックからの現在時刻を秒(tv_sec)とマイクロ秒(tv_usec)で取得し、それをミリ秒に変換しています。

この方法は、システムの現在時刻に基づいており、ハードウェアやOSの影響を受ける可能性があります。

○サンプルコード4:高精度タイマーの使用

高精度タイマーを使用することで、C++における時間測定の精度をさらに高めることができます。

特に、時間測定がクリティカルなアプリケーションや、微妙なタイミングを要するタスクには、この手法が適しています。

下記のサンプルコードは、高精度タイマーを用いてミリ秒単位で時間を測定する方法を表しています。

#include <iostream>
#include <chrono>

int main() {
    auto start = std::chrono::steady_clock::now();

    // 高精度で時間を測定したい処理をここに記述

    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double, std::micro> elapsed = end - start;
    std::cout << "経過時間: " << elapsed.count() << " µs" << std::endl;

    return 0;
}

この例ではstd::chrono::steady_clockを使用しています。

これはシステムの時間変更に影響されず、より安定した時間測定が可能です。

経過時間はマイクロ秒単位で出力されていますが、これをミリ秒単位に変更することも容易です。

○サンプルコード5:マルチスレッド環境での時間計測

マルチスレッド環境では、複数のスレッドが同時に走るため、各スレッドの実行時間を正確に測定することが重要です。

下記のサンプルコードは、マルチスレッド環境における時間計測の一例を表しています。

#include <iostream>
#include <chrono>
#include <thread>
#include <vector>

void do_work() {
    // スレッドごとの作業をここに記述
}

int main() {
    std::vector<std::thread> threads;
    std::vector<std::chrono::duration<double, std::milli>> times(10);

    for (int i = 0; i < 10; ++i) {
        threads.emplace_back([&, i]() {
            auto start = std::chrono::steady_clock::now();

            do_work();

            auto end = std::chrono::steady_clock::now();
            times[i] = end - start;
        });
    }

    for (auto& thread : threads) {
        thread.join();
    }

    for (const auto& time : times) {
        std::cout << "スレッドの実行時間: " << time.count() << " ms" << std::endl;
    }

    return 0;
}

このコードでは、10個のスレッドがそれぞれdo_work関数を実行し、各スレッドの実行時間をミリ秒単位で測定しています。

マルチスレッド環境では、各スレッドの開始と終了時間を個別に記録することで、正確な時間計測を行うことが可能です。

●時間取得の応用例

C++でミリ秒単位の時間取得技術は、さまざまな応用が可能です。

特にパフォーマンスの重要なアプリケーションや、タイムセンシティブな操作が必要な場面では、精度の高い時間管理が求められます。

ここでは、具体的な応用例として、パフォーマンスモニタリング、イベント駆動プログラミング、ゲームやアニメーションでの利用方法を紹介します。

○サンプルコード6:パフォーマンスモニタリング

C++での時間計測は、システムやアプリケーションのパフォーマンスモニタリングにおいて重要な役割を果たします。

下記のサンプルコードは、特定の処理の実行時間をミリ秒単位で計測する方法を表しています。

#include <iostream>
#include <chrono>

int main() {
    auto start = std::chrono::high_resolution_clock::now();

    // モニタリングしたい処理をここに記述

    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::milli> elapsed = end - start;
    std::cout << "処理時間: " << elapsed.count() << " ms" << std::endl;

    return 0;
}

このコードでは、<chrono>ライブラリを使用して高精度のタイマーを作成し、処理の開始と終了時刻を記録しています。

経過時間はミリ秒単位で表示され、パフォーマンス分析に役立ちます。

○サンプルコード7:時間依存のイベント処理

時間依存のイベント処理では、特定の時間が経過した後にイベントを発生させることができます。

下記のサンプルコードは、指定したミリ秒後に処理を実行する方法を表しています。

#include <iostream>
#include <chrono>
#include <thread>

void timedEvent(int milliseconds) {
    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
    std::cout << milliseconds << "ミリ秒経過後のイベント" << std::endl;
}

int main() {
    timedEvent(1000);  // 1000ミリ秒後にイベントを実行
    return 0;
}

このコードでは、sleep_for関数を使用して指定した時間だけスレッドを停止させ、その後イベントを実行しています。

これはタイマーや遅延実行機能を実装する際に有効です。

○サンプルコード8:ゲームやアニメーションでの利用

ゲームやアニメーションでは、フレームレート管理やアニメーションの同期など、時間が重要な要素となります。

下記のサンプルコードは、フレームレートを管理するための基本的な構造を表しています。

#include <iostream>
#include <chrono>
#include <thread>

int main() {
    const int fps = 60;
    const std::chrono::milliseconds frameTime(1000 / fps);

    while (true) {
        auto frameStart = std::chrono::steady_clock::now();

        // フレーム更新処理をここに記述

        auto frameEnd = std::chrono::steady_clock::now();
        auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(frameEnd - frameStart);
        if (elapsedTime < frameTime) {
            std::this_thread::sleep_for(frameTime - elapsedTime);
        }
    }

    return 0;
}

このコードは、一定のフレームレート(この場合は60FPS)でゲームやアニメーションを実行するためのものです。

各フレームの処理時間を計測し、必要に応じてスレッドをスリープさせることで、一定の間隔でフレームを更新しています。

●時間取得時の注意点と対処法

C++での時間取得は、精確で効果的な方法ですが、いくつかの注意点があります。

異なるプラットフォームや環境において正確な時間を取得するためには、特定の考慮事項を理解し対処する必要があります。

○プラットフォームによる違いと対応

異なるプラットフォームでは、時間取得のメカニズムが異なることがあります。

Windows、Linux、macOSなど、異なるオペレーティングシステムでは、時間に関連するAPIやライブラリが異なる場合があります。

例えば、WindowsではQueryPerformanceCounterGetTickCountといった関数が利用できるのに対し、UNIXベースのシステムではgettimeofdayclock_gettimeが使用されます。

クロスプラットフォームのアプリケーションを開発する際には、このような違いを考慮し、条件に応じた適切な時間取得関数を選択する必要があります。

○精度とパフォーマンスのバランス

時間取得の精度とアプリケーションのパフォーマンスはトレードオフの関係にあります。

高い精度を求める場合、システムリソースへの影響が大きくなることがあります。

特に、高精度のタイマーを頻繁に呼び出すと、CPUの使用率が上がりパフォーマンスに影響を与える可能性があります。

したがって、必要以上の精度を追求するよりも、アプリケーションの要件に合わせて適切な精度レベルを選択することが重要です。

○タイムゾーンと夏時間の考慮

グローバルなアプリケーションでは、タイムゾーンや夏時間(デイライトセービングタイム)の影響を考慮する必要があります。

タイムゾーンによっては、同じ絶対時間でも異なるローカル時間が表示されるため、ユーザーの地域に合わせた時間表示を行う必要があります。

また、夏時間の開始と終了は国や地域によって異なるため、これらの変更を適切に取り扱うための処理が必要です。

C++の<chrono>ライブラリやタイムゾーンを扱うサードパーティのライブラリを使用して、これらの問題に対処することができます。

まとめ

この記事では、C++を使用してミリ秒単位で時間を取得する多様な方法を詳細に解説しました。

<chrono>ライブラリの活用、clock()関数の使用、システムクロックの利用、高精度タイマーの導入、マルチスレッド環境での時間計測など、さまざまな手法を紹介しました。

さらに、パフォーマンスモニタリング、イベント処理、ゲームやアニメーションでの応用例も掘り下げ、プラットフォームによる違いへの対応、精度とパフォーマンスのバランス、タイムゾーンや夏時間への対応などの注意点も紹介しました。

最後に、自作のタイマー関数の作成、時間取得関数の最適化、クロスプラットフォーム対応といったカスタマイズ方法についても説明しました。

これらの知識を活用して、C++プログラミングの精度と効率を高めることができます。