2. 김용준
- 실제 문제는 선행 태스크와 후행 태스크가 1:1 대응이 아닌 경우가 많음
- 여러 태스크의 작업 완료 여부에 따라서 n:1 연결을 할 수 있음
- Concurrency::when_all, Concurrency::when_any를 이용해서 해결
태스크 집합의 Join과 Select
PPL Study: Composing Tasks
PPL Study: Composing Tasks
4. 김용준
Concurrency::when_any (ppltask.h)
PPL Study: Composing Tasks
PPL Study: Composing Tasks
template<typename _Iterator>
auto when_any(_Iterator _Begin, _Iterator _End)
-> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type,
_Iterator>::_Perform(nullptr, _Begin, _End))
{
typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(nullptr, _Begin, _End);
}
template<typename _Iterator>
auto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken)
-> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type,
_Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End))
{
typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End);
}
여담
when_all과 when_any를 잘보면 template<typename _Iterator>에서 template과 angle bracket(<) 사이에 space가 있을 때도 있고 없을
때도 있네요 ㅋㅋ. 이런 인간적인 실수가 ㅋㅋ.
5. 김용준
PPL Study: Composing Tasks
PPL Study: Composing Tasks
VS2012 provide two overrided functions
template <typename _Iterator>
auto when_all(_Iterator _Begin, _Iterator _End) { ... }
template <typename _Iterator>
auto when_all(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken) { ... }
VS2013, 2015 provide this function
auto when_all (_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options() )
- VS2012의 ppltask.h와 VS2013, 2015가 약간 다름
- task_options은 VS2013에서 새로 추가된 클래스
- task_options has cancellation_token의 형태 (딴것도 많이 갖고 있음)
- 안에 뜯어보면 이거 저거 할말이 많을 것 같던데, 다음주 나오니 궁금해도
참아주세요~
잠깐: VS2012 vs Upper version
6. 김용준
PPL Study: Composing Tasks
PPL Study: Composing Tasks
template <typename _Iterator>
auto when_***(_Iterator _Begin, _Iterator _End) { ... }
template <typename _Iterator>
auto when_***(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken) { ... }
_Iterator
The type of the input iterator.
_Begin
The position of the first element in the range of elements to be combined into the resulting task.
_End
The position of the first element beyond the range of elements to be combined into the resulting task.
_CancellationToken
The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token,
the resulting task will be created with a token that is a combination of all the cancelable tokens (tokens created by
methods other than cancellation_token::none() of the tasks supplied.
반환 된 작업의 취소를 제어 하는 취소 토큰입니다. 취소 토큰을 제공 하지 않으면, 취소될 수 있는 모든 토큰의 조합으로 결과 작업이
만들어 집니다. (토큰 이외의 방법을 사용하여 만든 cancellation_token::none()제공 하는 작업입니다.) – 음 번역이 어렵네요 –ㅁ-
when_all & when_any, Parameters (MSDN VS2012)
7. 김용준
PPL Study: Composing Tasks
PPL Study: Composing Tasks
template <typename _Iterator>
auto when_all(_Iterator _Begin, _Iterator _End) { ... }
template <typename _Iterator>
auto when_all(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken) { ... }
Return value
A task that completes sucessfully when all of the input tasks have completed successfully. If the input tasks are of
type T, the output of this function will be a task<std::vector<T>>. If the input tasks are of type void the output task
will also be a task<void>.
모든 입력된 작업이 성공적으로 완료 되면 성공적으로 완료 되는 작업입니다. 입력된 작업 형식이 T인 경우, 이 함수의 출력은
task<std::vector<T>>가 됩니다. 입력된 작업 형식이 void인 경우 출력 작업 또한 task<void>가 됩니다.
Remarks
If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state,
and the exception, if one is encoutered, will be thrown if you call get() or wait() on that task.
작업 중 하나가 작업이 취소 되거나 예외가 throw 됩니다. 반환 된 작업에서 취소 상태를 조기에 완료 및 오류가 발생 한 경우 호출 하는
경우는 예외가 throw 됩니다 경우 get() 또는 wait() 작업을 합니다. – 으억 이거 번역이 왜이럼... 번역을 못하겠습니다. ㅠㅠ
when_all Return value, Remarks (MSDN VS2012)
8. 김용준
PPL Study: Composing Tasks
PPL Study: Composing Tasks
template <typename _Iterator>
auto when_any(_Iterator _Begin, _Iterator _End) { ... }
template <typename _Iterator>
auto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken) { ... }
Return value
A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are
of type T, the output of this function will be a task<std::pair<T, size_t>>, where the first element of the pair is the
result of the completing task, and the second element is the index of the task that finished. If the input tasks are of
type void the output is a task<size_t>, where the result is the index of the completing task.
입력 작업 중 하나가 성공적으로 완료되는 경우 완료되는 작업입니다. 입력 작업의 형식이 T인 경우 해당 함수의 출력은
task<std::pair<T, size_t>>가 됩니다. pair의 첫 번째 요소는 완료 중인 작업의 결과가 되고 두 번째 요소는 완료된 작업의 인덱스가 됩
니다. 입력 작업이 형식 void인 경우 출력은 task<size_t>로 여기서 결과는 완료 중인 작업의 인덱스입니다.
when_any Return value, Remarks (MSDN VS2012)
9. 김용준
#include <ppltasks.h>
#include <array>
#include <iostream>
#include <numeric>
using namespace Concurrency;
using namespace std;
int wmain()
{
// 세 개의 태스크를 생성하여 병렬로 실행
array<task<int>, 3> tasks =
{
create_task([]() -> int { return 88; }),
create_task([]() -> int { return 42; }),
create_task([]() -> int { return 99; })
};
int sum = 0;
// when_all 함수를 호출하여 세 개의 태스크가
// 모두 완료될 때까지 대기
auto joinTask = when_all(begin(tasks), end(tasks));
When_all Example (in book)
PPL Study: Composing Tasks
PPL Study: Composing Tasks
// 모든 태스크가 완료된 이후에 실행될 태스크 지정
joinTask.then([&sum](vector<int> results)
{
// 세 개의 태스크의 결과 값 합산
sum = accumulate(begin(results), end(results), 0);
}).wait();
// 결과 값 출력
wcout << L"The sum is "<< sum << L"." << endl;
}
auto joinTask = when_all(begin(tasks), end(tasks));
를
auto joinTask = tasks[0] && tasks[1] && tasks[2];
로 변경 가능
10. 김용준
#include <ppltasks.h>
#include <array>
#include <iostream>
using namespace Concurrency;
using namespace std;
int wmain()
{
// 세 개의 태스크를 생성하여 병렬로 실행
array<task<int>, 3> tasks =
{
create_task([]() -> int { return 88; }),
create_task([]() -> int { return 42; }),
create_task([]() -> int { return 99; })
};
// when_any 함수를 호출하여 가장 먼저 완료되는 태스크를 선택
auto selectTask = when_any(begin(tasks), end(tasks));
// 선택된 태스크 완료 이후에 실행될 태스크 지정
selectTask.then([](pair<int, size_t> result)
{
wcout << "First task to finish returns "
<< result.first
<< L" and has index "
<< result.second
<< L'.' << endl;
}).wait();
}
When_any Example (in book)
PPL Study: Composing Tasks
PPL Study: Composing Tasks
auto selectTask = when_any(begin(tasks), end(tasks));
를
auto selectTask = tasks[0] || tasks[1] || tasks[2];
로 변경 가능
11. 김용준
정리
- when_all은 작업 집합이 완료될때 완료되는 작업을 생성
- when_any은 작업 집합의 첫번째 작업이 완료될때 완료되는 작업을 생성
- when_all과 when_any는 각각 &&과 || 연산자로 대체 할 수 있다.
실무 예시 ㅋㅋ
- when_all의 경우 대부분의 상황에 사용될 수 있을듯 (설계, 부재력 등등)
- when_any는 배근 산정에 사용할 수도 있을 것 같은데... 생각해봅시다
Composing Tasks
PPL Study: Composing Tasks
PPL Study: Composing Tasks
12. 김용준
교재
Think About PPL을 이용한 VC++병렬 프로그래밍 (한빛미디어)
MSDN
https://msdn.microsoft.com/ko-kr/library/dd492427.aspx
참고 자료
PPL Study: Composing Tasks
PPL Study: Composing Tasks