C++ STL - Concurrency[7]
이번 시간에는 STL의 동시성 처리 관련 라이브러리를 살펴보겠습니다.
Thread
1. 기본
-
헤더 :
-
std::this_thread
- get_id() : 스레드 ID 반환
- sleep_for : duration 동안 스레드 pause
- sleep_until : time_point 동안 스레드 pause
- yield() : 다른 스레드 스케쥴링
int main()
{
thread::id id = this_thread::get_id();
cout << id << endl;
this_thread::sleep_for( 3s );
this_thread::sleep_until( chrono::system_clock::now() + 3s);
this_thread::yield();
}
2. 생성 방법
- 기본
#include <iostream>
#include <thread>
using namespace std;
void foo()
{
cout << "thread start" << endl;
this_thread::sleep_for(2s);
cout << "thread end" << endl;
}
int main()
{
thread t(&foo);
t.join(); // 스레드 종료 대기.
//t.detach(); // join과 같지만 주 스레드가 종료되면 같이 종료됨
}
- 멤버 함수도 수행 가능
#include <iostream>
#include <thread>
using namespace std;
void f1() {}
void f2(int a) {}
struct Worker
{
void Main() {}
};
struct Functor
{
void operator()() {}
};
int main()
{
thread t1(&f1);
thread t2(&f2, 5);
Worker w;
thread t3(&Worker::Main, &w);
Functor f; f();
thread t4(f);
thread t5( []() {cout << "thread t5" << endl;});
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
}
3. Synchronization
- mutex
#include <iostream>
#include <thread>
#include <string>
#include <mutex>
using namespace std;
int global = 0;
mutex m;
void f1()
{
lock_guard<mutex> lg(m); // 생성자에서 m.lock, 소멸자에서 m.unlock
//m.lock();
global = 100;
global = global + 1;
//m.unlock();
}
int main()
{
thread t1(&f1);
thread t2(&f1);
t1.join();
t2.join();
}
- promise, future
- promise : 값을 받을 수 있다는 약속
- future : 미래의 결과값이 담길 예정인 객체
#include <iostream>
#include <thread>
#include <future>
using namespace std;
void f1( promise<int>& p )
{
this_thread::sleep_for(3s);
p.set_value(10);
}
int main()
{
promise<int> p;
future<int> ft = p.get_future();
thread t(&f1, ref(p));
cout << "wait value " << endl;
cout << "value : " << ft.get() << endl; // 대기
t.join();
}
async
1. 스레드를 생성하는 2가지 방법
- thread 클래스 사용 - low level api
- async 함수 사용 - high level api
- async 객체의 소멸자에서 내부적으로 get()이 발생
#include <iostream>
#include <thread>
#include <future>
using namespace std;
int f1()
{
this_thread::sleep_for(3s);
return 10;
}
int main()
{
future<int> ft = async( launch::async, &f1);
cout << "main routine" << endl;
}
2. std::launch
-
launch policty
- launch::async : 비동기로 실행(스레드 생성) , 생성 실패시 예외 발생
- launch::deferred: 지연된 실행(get() 호출시)
- launch::async | launch::deferred : 생성이 가능하면 생성, 그렇지 않으면 지연된 실행
int f1() { cout << "f1 : " << this_thread::get_id() << endl; this_thread::sleep_for(3s); return 10; } int main() { cout << "main : " << this_thread::get_id() << endl; //future<int> ft = async( launch::async, &f1); // f1을 지연된 실행(get을 호출할때). //future<int> ft = async( launch::deferred, &f1); future<int> ft = async( launch::deferred | launch::async, &f1); this_thread::sleep_for(1s); cout << "main routine" << endl; cout << ft.get() << endl; }
3. asnyc의 return 값을 수령하지 않았을 때
- async의 리턴값 임시객체의 소멸자에서 get이 호출되므로 해당 라인에서 block됨
#include <iostream>
#include <thread>
#include <future>
using namespace std;
int f1()
{
this_thread::sleep_for(3s);
cout << "f1 end" << endl;
return 10;
}
int main()
{
async( launch::async, &f1); // 리턴값으로 future<int> 객체
// 이 라인에서 block 되버림
future<int> ft = async( launch::async, &f1);
cout << "main routine" << endl;
}