std::thread 스레드 만들기
#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(); // OR t.detach();
}
매개변수 넘기기
#include <iostream>
#include <thread>
#include <string>
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)); // 그냥 n으로 넘기면 안됨을 기억
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;
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가 지원하는 함수
#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(); // CPU가 지원하는 thread개수
std::cout << n << std::endl;
std::thread t(&foo);
std::this_thread::sleep_for(1s);
std::thread::id tid = t.get_id();
std::cout << tid << std::endl;
t.join();
}
native_handle_type
std::thread의 thread우선순위를 변경할수 있을까?
C++ 표준에서는 미지원 OS의 도움을 받아야한다.
#include <iostream>
#include <thread>
#include <windows.h>
#include <chrono>
using namespace std::literals;
void foo()
{
// thread의 핸들 얻기
auto tid = std::this_thread::get_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(); // OS의 스레드 핸들 반환
std::cout << "ID : " << t.get_id() << std::endl;
std::cout << "handle : " << h << std::endl;
std::this_thread::sleep_for(100ms);
// thread의 우선순위 변경
SetThreadPriority(h, THREAD_PRIORITY_TIME_CRITICAL);
t.join();
}
thread 복사와 이동
#include <thread>
void foo() {}
void goo() {}
int main()
{
std::thread t1(&foo);
std::thread t2(&goo);
t1.swap(t2);
// t1 : goo / t2 : foo 실행
std::thread t3 = t1; // Error
std::thread t4 = std::move(t1);
//t1.join();
t2.join();
t3.join();
}
std::ref
#include <iostream>
#include <functional>
void foo(int& a) { a = 200; }
template<typename T> void call_foo(T arg)
{
foo(arg);
}
int main()
{
int n = 0;
//foo(n);
call_foo(n); // n이 복사본이 넘어가게 된다.
std::cout << n << std::endl; // 0
}
call_foo(n);
를 해도 값 변화가 나타나게 하고 싶다면?
#include <iostream>
#include <functional>
void foo(int& a) { a = 200; }
template<typename T> void call_foo(T arg)
{
foo(arg);
}
int main()
{
int n = 0;
call_foo(std::ref(n));
std::cout << n << std::endl; // 200
// 이게 어떻게 가능하지?
}
어떻게 가능한지 구현하며 설명
#include <iostream>
template<typename T> struct reference_wrapper
{
T* obj
public:
reference_wrapper(T& t) : obj(&t) {} // 참조로 받아서 그 주소를 보관한다
operator T&() { return *obj; }
};
int main()
{
int n = 0;
reference_wrapper<int> rw = n;
int& r = rw; // operator T&()가 호출됨
r = 100;
std::cout << n << std::endl; // 100
}
결국 객체를 주소로 보관하다가 T&로 암시적변환해서 리턴해준다가 핵심
// 3. foo에서 a의 참조형을 받기에 reference_wrapper에서 관리하던 참조형 리턴
void foo(int& a) { a = 200; }
template<typename T> void call_foo(T arg)
// 2.
// T : reference_wrapper가 되고 arg는 reference_wrapper형태로 하나 더 복사된다.
// 단, 복사되며 내부에 가지고 있던 n의 주소값도 같이 복사가 된다(핵심)
{
foo(arg);
}
int main()
{
int n = 0;
reference_wrapper<int> rw = n; // 1. rw에서 n의 주소를 담고있다
call_foo(rw);
std::cout << n << std::endl;
}