<chrono> 시간 측정 & 타이머
C++ <chrono>는 타입 안전한 시간 계산을 위한 라이브러리입니다. 정수나 double로 시간을 다루던 구식 방식 대신, 단위 변환 실수를 컴파일 타임에 잡아줍니다.
핵심 3요소
섹션 제목: “핵심 3요소”Clock ──produces──▶ time_point ──difference──▶ duration| 개념 | 설명 | 예시 |
|---|---|---|
Clock | 현재 시각을 제공하는 시계 | steady_clock, system_clock |
time_point | 특정 시각 (Epoch 기준) | steady_clock::now() |
duration | 두 시각의 차이 | milliseconds(100) |
Clock 종류
섹션 제목: “Clock 종류”#include <chrono>using namespace std::chrono;
// 단조증가 시계 — 성능 측정에 사용 (시스템 시간 변경 영향 없음)auto t1 = steady_clock::now();
// 시스템 시계 — 실제 시각 표현 (UTC 기준)auto now = system_clock::now();
// 고해상도 시계 — 플랫폼에 따라 steady_clock과 동일할 수 있음auto t = high_resolution_clock::now();성능 측정에는 반드시 steady_clock을 사용하세요. system_clock은 NTP 동기화나 사용자 조작으로 역행할 수 있습니다.
Duration 단위와 변환
섹션 제목: “Duration 단위와 변환”#include <chrono>using namespace std::chrono;
duration<long long, std::nano> ns(1000); // 1000 나노초duration<long long, std::micro> us(500); // 500 마이크로초duration<long long, std::milli> ms(250); // 250 밀리초duration<long long> sec(10); // 10 초duration<long long, std::ratio<60>> min(5); // 5 분
// 편의 타입 별칭nanoseconds n(1000);microseconds u(500);milliseconds m(250);seconds s(10);minutes m2(5);hours h(2);단위 변환
섹션 제목: “단위 변환”auto ms = milliseconds(1500);
// 정밀도 손실 없는 변환 (작은 → 큰 단위는 암시적)seconds sec = duration_cast<seconds>(ms); // 1 (소수 버림)
// 명시적 변환 필요 (큰 → 작은 단위는 암시적 OK)auto us = microseconds(ms); // 1500000
// 부동소수점 durationduration<double> fsec = ms; // 1.5chrono_literals (C++14)
섹션 제목: “chrono_literals (C++14)”using namespace std::chrono_literals;
auto delay = 100ms; // milliseconds(100)auto period = 1s; // seconds(1)auto wait = 500us; // microseconds(500)auto big = 2h + 30min + 15s; // 복합 연산
// std::this_thread::sleep_for와 함께#include <thread>std::this_thread::sleep_for(50ms);성능 측정 패턴
섹션 제목: “성능 측정 패턴”기본 패턴
섹션 제목: “기본 패턴”#include <chrono>#include <iostream>
template <typename Func>auto benchmark(Func&& f) { using namespace std::chrono; auto start = steady_clock::now(); f(); auto end = steady_clock::now(); return duration_cast<microseconds>(end - start);}
int main() { auto elapsed = benchmark([]() { volatile int sum = 0; for (int i = 0; i < 1'000'000; ++i) sum += i; }); std::cout << "Elapsed: " << elapsed.count() << " us\n";}RAII 타이머
섹션 제목: “RAII 타이머”#include <chrono>#include <iostream>#include <string>
class ScopedTimer {public: explicit ScopedTimer(std::string label) : label_(std::move(label)) , start_(std::chrono::steady_clock::now()) {}
~ScopedTimer() { auto end = std::chrono::steady_clock::now(); auto us = std::chrono::duration_cast<std::chrono::microseconds>( end - start_).count(); std::cout << label_ << ": " << us << " us\n"; }
private: std::string label_; std::chrono::steady_clock::time_point start_;};
// 사용void expensiveOp() { ScopedTimer t("expensiveOp"); // ... 코드 ...}반복 평균 측정
섹션 제목: “반복 평균 측정”template <int N = 10, typename Func>double benchmark_avg(Func&& f) { using namespace std::chrono; double total = 0; for (int i = 0; i < N; ++i) { auto start = steady_clock::now(); f(); auto end = steady_clock::now(); total += duration<double, std::micro>(end - start).count(); } return total / N;}타임아웃 구현
섹션 제목: “타임아웃 구현”#include <chrono>#include <mutex>#include <condition_variable>
std::mutex mtx;std::condition_variable cv;bool ready = false;
void waitWithTimeout() { using namespace std::chrono_literals; std::unique_lock lock(mtx);
// 최대 500ms 대기 if (cv.wait_for(lock, 500ms, []{ return ready; })) { std::cout << "조건 충족\n"; } else { std::cout << "타임아웃\n"; }}C++20 Calendar & Timezone
섹션 제목: “C++20 Calendar & Timezone”C++20에서 날짜/시간 계산 API가 크게 확장되었습니다.
#include <chrono>using namespace std::chrono;
// 날짜 리터럴 (C++20)auto d = 2024y / January / 15; // year_month_dayauto d2 = 2024y / 1 / 15;
// 오늘 날짜auto today = floor<days>(system_clock::now());year_month_day ymd{today};std::cout << ymd.year() << "-" << static_cast<unsigned>(ymd.month()) << "-" << static_cast<unsigned>(ymd.day()) << "\n";
// 날짜 연산auto next_month = ymd.year() / (ymd.month() + months(1)) / ymd.day();
// 타임존 (C++20)auto tz = locate_zone("Asia/Seoul");auto now = zoned_time{tz, system_clock::now()};std::cout << now << "\n"; // 2024-01-15 14:30:00 KST특정 날짜까지 남은 시간
섹션 제목: “특정 날짜까지 남은 시간”auto deadline = sys_days{2024y / December / 31};auto now_days = floor<days>(system_clock::now());auto remaining = deadline - now_days;std::cout << remaining.count() << "일 남음\n";게임 루프 프레임 타이머
섹션 제목: “게임 루프 프레임 타이머”#include <chrono>
class GameTimer {public: using Clock = std::chrono::steady_clock;
GameTimer() : last_(Clock::now()) {}
// 매 프레임 호출 — deltaTime(초) 반환 float tick() { auto now = Clock::now(); float dt = std::chrono::duration<float>(now - last_).count(); last_ = now; return dt; }
// 경과 시간 (초) float elapsed() const { return std::chrono::duration<float>(Clock::now() - start_).count(); }
private: Clock::time_point start_ = Clock::now(); Clock::time_point last_;};
// 사용GameTimer timer;while (running) { float dt = timer.tick(); update(dt); // dt: 프레임 간 경과 시간 render();}자주 하는 실수
섹션 제목: “자주 하는 실수”// 잘못된 예 — system_clock으로 성능 측정auto t1 = std::chrono::system_clock::now();doWork();auto t2 = std::chrono::system_clock::now();// NTP 조정 시 음수가 나올 수 있음!
// 올바른 예auto t1 = std::chrono::steady_clock::now();doWork();auto t2 = std::chrono::steady_clock::now();auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);핵심 요약
섹션 제목: “핵심 요약”- 성능 측정 →
steady_clock - 실제 시각 표현 →
system_clock - 단위 변환 →
duration_cast<>또는 부동소수점duration<double> - 리터럴 →
using namespace std::chrono_literals+100ms,1s - C++20 날짜 →
year_month_day,zoned_time