C++ Concurrent - Thread Basic[1]
본 시리즈는 C++ 기반의 동시성 프로그래밍에 관한 내용입니다. 이번 시간에는 std::this_tread, chrono에 관해 살펴보겠습니다.
std::this_tread
get_id()
- 현재 실행중인 스레드의 ID 반환
- 정수로 변환 불가(구조체 형식으로 리턴됨)
#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(tid1) << std::endl;
}
- sleep_for() / sleep_until()
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::literals;
std::chrono::system_clock::time_point
createDateTime(int year, int month, int day, int hour, int minute, int second);
int main()
{
std::this_thread::sleep_for(std::chrono::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 );
auto tp2 = createDateTime(2021, 4, 11, 12, 39, 00);
std::this_thread::sleep_until( tp2 );
}
time_t toUTC(std::tm& timeinfo)
{
#ifdef _WIN32
std::time_t tt = _mkgmtime(&timeinfo);
#else
time_t tt = timegm(&timeinfo);
#endif
return tt;
}
std::chrono::system_clock::time_point
createDateTime(int year, int month, int day, int hour, int minute, int second)
{
tm timeinfo1 = tm();
timeinfo1.tm_year = year - 1900;
timeinfo1.tm_mon = month - 1;
timeinfo1.tm_mday = day;
timeinfo1.tm_hour = hour;
timeinfo1.tm_min = minute;
timeinfo1.tm_sec = second;
tm timeinfo = timeinfo1;
time_t tt = toUTC(timeinfo);
return std::chrono::system_clock::from_time_t(tt);
}
- yield()
- 현재 스레드의 흐름을 다른 스레드에 양보
#include <iostream>
#include <chrono>
#include <thread>
using namespace std::literals;
void mysleep(std::chrono::microseconds us)
{
auto target = std::chrono::high_resolution_clock::now() + us;
while (std::chrono::high_resolution_clock::now() < target)
std::this_thread::yield();
}
int main()
{
mysleep(1s);
}
std::tread
스레드 생성 방법
- std::thread의 생성 인자로 스레드를 수행할 함수 전달
- join() 또는 detach()를 해야함
- join() : 스레드 종료를 대기
- detach() : 생성된 스레드가 독립적으로 실행(메인 스레드 종료시 같이 종료됨)
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::literals;
void foo()
{
for( int i = 0; i < 10; i++)
{
std::cout << "foo : " << i << std::endl;
std::this_thread::sleep_for(100ms);
}
}
int main()
{
std::thread t(&foo);
// t.join();
t.detach();
std::cout << "end" << std::endl;
int n;
std::cin >> n;
}
- 인자 전달 방법
#include <iostream>
#include <string>
#include <thread>
void f1() { }
void f2(int a, double d) { }
void f3(int a, int& b, std::string&& s) { b = 100;}
int main()
{
int n = 0;
std::string s = "hello";
std::thread t1(&f1);
std::thread t2(&f2, 10, 3.4);
std::thread t3(&f3, 10, std::ref(n), std::move(s) );
t1.join();
t2.join();
t3.join();
std::cout << s << std::endl; // ""
std::cout << n << std::endl; // 100
}
- callable object 전달 방법
#include <iostream>
#include <thread>
void foo(int a, double d) {}
struct Machine
{
void Run(int a, double d) {}
};
struct Work
{
void operator()(int a, double b) const {}
};
int main()
{
Machine m;
Work w; w(1, 3.4); // 함수객체
std::thread t1( &foo, 1, 3.4 );
std::thread t2( &Machine::Run, &m, 1, 3.4 );
std::thread t3( w, 1, 3.4 );
std::thread t4( []{ std::cout << "lambda" << std::endl;} );
t1.join();
t2.join();
t3.join();
t4.join();
}
std::thread의 멤버 함수
hardware_concurrency() : CPU의 멀티 스레드 지원 개수
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::literals;
void foo()
{
std::cout << std::this_thread::get_id() << std::endl;
}
int main()
{
int n = std::thread::hardware_concurrency();
std::cout << n << std::endl; // 8
std::thread t( &foo );
std::this_thread::sleep_for(1s);
std::thread::id tid = t.get_id();
std::cout << "created thread id : " << tid << std::endl;
t.join();
}
GetCurrentThread : OS 레벨의 스레드 핸들 획득
- 스레드 우선순위 변경 등에 사용
#include <iostream>
#include <thread>
#include <windows.h>
#include <chrono>
using namespace std::literals;
void foo()
{
auto tid = std::this_thread::get_id(); // 스레드 ID 얻기
auto handle = GetCurrentThread();
std::this_thread::sleep_for(1s);
std::cout << GetThreadPriority( handle) << std::endl;
}
int main()
{
std::thread t( &foo );
std::thread::native_handle_type h = t.native_handle();
std::cout << "ID : " << t.get_id() << std::endl;
std::cout << "handle : " << h << std::endl;
std::this_thread::sleep_for(100ms);
SetThreadPriority((HANDLE)h, THREAD_PRIORITY_TIME_CRITICAL);
t.join();
}
joinable()
#include <iostream>
#include <thread>
int main()
{
std::thread t;
if ( t.joinable() )
{
t.join();
}
}
변수간 thread 객체 전달 방법
- copy 불가
#include <thread>
void foo() {}
void goo() {}
int main()
{
std::thread t1(&foo);
std::thread t2(&goo);
t1.swap(t2);
// std::thread t3 = t1; // error
std::thread t4 = std::move(t1); // ok
// t1.join(); // 예외.
t2.join();
t4.join();
}