I'm FanJae.

[C++ Concurrent] std::this_thread, std::chrono 본문

C++/Concurrent

[C++ Concurrent] std::this_thread, std::chrono

FanJae 2024. 9. 24. 22:38

1. std::this_thread namespace

- 스레드 관련 4개의 함수를 제공하는 namespace

- <thread> 헤더

std::this_thread::get_id() 현재 스레드의 ID 반환
std::this_thread::sleep_for() 주어진 시간 만큼 현재 스레드 재우기
std::this_thread::sleep_until() 주어진 시간 까지 현재 스레드 재우기
std::this_thread::yield() 다른 스레드를 실행할 수 있도록 힌트 제공

 

1-1. std::this_thread::get_id()

- 실행중인 현재 스레드의 ID를 반환한다.

std::thread_id  get_id() noexcept;
#include <iostream>
#include <thread>

int main()
{
    std::cout << std::this_thread::get_id() << std::endl;
    
    std::thread::id tid1 = std::this_thread::get_id();
    std::thread::id tid2 = std::this_thread::get_id();
    
    tid1 == tid2;
    tid1 < tid2;
    
    std::hash<std::thread::id> h;
    
    std::cout << h(td1) << std::endl;
}

① std::thread::id

- 스레드 ID를 나타내는 가벼운 구조체

- cout로 출력 가능하고 비교 연산도 가능하다.

- 정수로 변환이 안된다.

- std::hash<std::thread::id> 함수 객체가 제공되므로 unordered 컨테이너에 키 값으로 사용가능하다.

 

1-2. sleep_for(), sleep_until()

sleep_for() 주어진 시간 만큼 현재 스레드 멈추기(재우기)
sleep_until() 주어진 시간 까지 현재 스레드 멈추기(재우기)

 

template <class Rep, class Period >
void sleep_for ( const std::chrono::duration<Rep, Period>& sleep_duration);

template <class Rep, class Duration >
void sleep_until ( const std::chrono::time_point<Clock, Duration>& sleep_time);

- 위와 같은 형태이다.

 

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

using namespace std::literals;

int main()
{
    std::this_thread::sleep_for(std::chronno::seconds(3));
    std::this_thread::sleep_for(3s); // 3ms, 3ns, 3min
    // std::this_thread::sleep_for(3); // error
    
    std::chrono::time_point tp1 = std::chrono::steady_clock::now();
    std::this_thread::sleep_until( tp1 + 2000ms);
}

- sleep_for를 사용할 때는 단순 숫자만 넘기면 std::chrono 형태가 아니기 때문에 오류가 발생한다.

- sleep_until은 특정 시간을 구해서 사용할 수 있다.

 

1-3. std::this_thread::yield()

- 다른 스레드에 실행 흐름을 양보할때 사용한다.

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

using namespace std::literals;

void mysleep(std::chrono::microseconds us) // micro 단위 초 인자.
{
     auto target = std::chrono::high_resolution_clock::now() + us;
     // 현재 시간 구한 이후 10ms을 더함.
     
     while (std::chrono::high_resolution_clock::now() < target) 
     {
           std::this_thread::yield(); // 실행 흐름을 다른 스레드에게 양보.
     }
     // 주기적으로 깨어나서 시간을 체크하고 목표시간이 안되면 계속 양보함.
}

int main()
{
    mysleep(1s);
}

 


2. chrono

2-1. chrono 라이브러리

- 시간을 다루는 C++ 표준 라이브러리이다.

- <chrono> 헤더

- std::chrono namespace 사용한다.

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

int main()
{
    std::chrono::hours         h(10);
    std::chrono::minutes       m(10);
    std::chrono::seconds      s1(10);
    std::chrono::milliseconds s2(10);
    std::chrono::nanoseconds  s3(10);
    
    
    std::cout << s1.count() << std::endl;
    
    std::chrono::duration<long long> d1(10);
}

 

※ chrono 라이브러리의 모든 시간 타입은 duration<>의 alias이다.

using nanoseconds    = duration<long long, nano>;
using microseconds   = duration<long long, micro>;
using milliseconds   = duration<long long, milli>;
using seconds        = duration<long long>;
using minutes        = duration<int, ratio<60>>;
using hours          = duration<int, ratio<3600>>;

 

- sleep_for를 보면, alias가 아닌 실제로는 chrono::duration으로 되어 있음을 확인할 수 있다.

 

- 이외에도 chrono 용 user define literal이 존재한다. 10s, 10ms, 10ns, 10min, 10h 등이 존재한다.

- using namespace std::literals 

 

이와 같은 이유로 sleep_for()를 사용하는 방법은 크게 3가지라고 볼 수 있다.

std::this_thread::sleep_for( std::chrono::seconds(3) );
std::this_thread::sleep_for( 3s );
std::this_thread::sleep_for( std::chrono::duration<long, long>(3) );

 

2-2. time_point

- 앞서 sleep_until() 함수의 경우는 std::chrono::time_point를 사용했다.

#include <iostream>
#include <chrono>
#include <thread>
using namespace std::literals;

int main()
{
    std::chrono::time_point tp1 = std::chrono::system_clock::now();

    std::chrono::hours h = std::chrono::duration_cast<std::chrono::hours>(tp1.time_since_epoch()); // 1970년 1월 1일을 기준으로 몇시간이 지났는가?

    std::this_thread::sleep_for(3ms);
    std::this_thread::sleep_until(std::chrono::system_clock::now() + 200ms);
}
duration 값과 단위, 3(30, 1) -> 30초(seconds)
(30, 1/1000) -> 30 밀리초
using seconds = duration<long long, ratio<1, 1>>;
using millseconds = duration<long long, ratio<1, 1000>>;
time_point 기준 시간 + duration
epoch time : 1970년 1월 1일 + duration

 

- duration은 특정한 값과 단위가 존재하지만, time_point는 duration에 기준 시간이 존재한다.

Comments