Post List

2015년 1월 21일 수요일

Thread (또는 Async) 간의 통신방법 : promise/future

promise / future (Visual Studio 2012부터 사용가능)

그동안 Multi-thread Programming에서 가장 어려운 부분은 thread 간의 통신 방법이다.
Modern C++에서는 Task (threadasync) 간의 통신 방법에 대해서도 제공을 해 주었다.

사용법은 간단하다. 아래와 같은 3단계로 이루어져 있다.

1. promise<T>와 future<T>를 연결
2. promise<T>에 .set_value()
3. future<T>에서 .get()

#include <iostream>
#include <thread>
#include <future>
#include <utility>

using std::cout;
using std::endl;
using std::vector;
using std::promise;
using std::future;
using std::thread;
using std::ref;
using std::move;

void GetTestVector(promise<vector<int>>& p, int p_nStart, int p_nNum)
{
    vector<int> itemlist;

    for (int i = 0; i < p_nNum; ++i)
       itemlist.push_back(i + p_nStart);

    p.set_value(move(itemlist));
}

void main()
{
    promise<vector<int>> p;
    future<vector<int>> f = p.get_future();

    thread t(&GetTestVector, ref(p), 11, 7);
    t.detach();
    auto result = f.get();

    for (auto item : result)
       cout << "Get Values : " << item << endl;
}

예상한대로 값이 나왔다.



그런데 위 결과만 봤을 때 궁금한게 생겼다.
.set_value()와 .get()사이에 시간적 연관 관계가 있을까 ?
없다면 .get()하기 전에 무조건 .set_value()을 할 thread에 .join()을 이용해서 작업을 마쳐주고 해야하나 ?
그래서 몇가지 Test를 해보았는데, 결론부터 얘기하자면,
.join()없이 그냥 사용하더라도 .get()은 .set_value()을 한 다음에 수행이 된다.
아래 예제를 보고 확인을 해보자.

#include <iostream>
#include <thread>
#include <future>
#include <chrono>
#include <utility>

using std::cout;
using std::endl;
using std::vector;
using std::promise;
using std::future;
using std::thread;
using std::ref;
using std::move;
using std::this_thread::get_id;
using std::this_thread::sleep_for;

using namespace std::chrono;

void GetTestVector(promise<vector<int>>& p, int p_nStart, int p_nNum)
{
    cout << "GetTestVector : " << get_id() << endl;

    vector<int> v;

    for (int i = 0; i < p_nNum; ++i)
       v.push_back(i + p_nStart);

    p.set_value(move(v));

    cout << "End of GetTestVector" << endl;
}

void PrintTestVector(future<vector<int>>& f, thread& t)
{
    cout << "PrintTestVector : " << get_id() << endl;

    auto result = f.get();

    for (auto item : result)
       cout << "Get Values : " << item << endl;

    cout << "End of PrintTestVector" << endl;
}

void main()
{
    promise<vector<int>> p;
    future<vector<int>> f = p.get_future();

    thread t;
    thread t2(&PrintTestVector, ref(f), ref(t));

    sleep_for(milliseconds(500));

    t = thread(&GetTestVector, ref(p), 11, 7);

    t.join();
    t2.join();
}

.get()하는 쪽을 먼저 실행하고 0.5초 뒤에 .set_value()하는 쪽보다 실행을 시켰는데도 .set_value()을 하는 쪽이 먼저 실행 된 뒤에 .get()이 된것을 확인 가능하다.