이전 회에서는 PPL에 대한 개념을 간단하게 설명했고, 이번에는 PPL의 세가지 feature 중 태스크(Task)에 대해서 설명하려고 합니다. 태스크에 대한 설명은 이미
이전에 정재원님께서 블로그를 통해서 설명한 적이 있습니다. 정재원님의 글은 태스크 사용 예제 코드를 중심으로
설명한 것으로 저는 그 글에서 빠진 부분과 기초적인 부분을 좀 더 설명하려고 합니다.
태스크라는 것은 작업 단위라고 생각하면
좋을 것 같습니다. 작업이라는 것은 여러 가지가 될 수 있습니다. 피보나치
수 계산, 배열에 있는 숫자 더하기, 그림 파일 크기 변경
등 작고 큰 작업이 있습니다. 보통 크기가 큰 작업은 이것을 작은 작업 단위로 나누어 병렬 처리를 하기도
합니다.
PPL의 태스크는 작업을 그룹 단위로 묶어서 병렬로 처리하고 대기 및 취소를 할 수 있습니다.
태스크 핸들
태스크 핸들은 각각의 태스크 항목을 가리키며 PPL에서는 task_handle 클래스를 사용합니다. 이 클래스는 람다 함수 또는 함수 오브젝트 등을 태스크를 실행하는 코드로 캡슐화 합니다. 태스크 핸들은 캡슐화 된 태스크 함수의 유효 기간을 관리하기 때문에 중요합니다. 예를들면 태스크 그룹에 태스크 핸들을 넘길 때는 태스크 그룹이 완료 될때까지 유효해야합니다.
unstructured 와 structured Task Groups
태스크 그룹은 unstructured와 structured 두 개로 나누어집니다.
이 두개의 태스크 그룹의 차이는 스레드
세이프하냐 안하느냐의 차이입니다.
unstructured는 스레드 세이프 하고 structured는 스레드 세이프 하지 않습니다.
태스크 관련 예제에 자주 나오는 task_group 클래스는 unstructured 태스크 그룹이고, structured_task_group 클래스는 structured 태스크
그룹을 뜻합니다.
unstructured 태스크 그룹은 structured 태스크 그룹보다 유연합니다.
스레드 세이프 하며 작업 중 taks_group::wait를 호출하여 대기한 후 태스크를
추가한 후 실행할 수 있습니다. 그렇지만 성능면에서 structured
태스크 그룹이 스레드 세이프 하지 않으므로 unstructured 태스크 그룹보다 훨씬
더 좋으므로 적절하게 선택해서 사용해야 합니다.
structured 작업 그룹은 스레드 세이프 하지 않기 때문에 Concurrency Runtime에서는 몇가지
제한이 있습니다.
- structured 작업 그룹 안에 다른 structured 작업 그룹이 있을 경우 내부의 작업 그룹은 외부의
작업 그룹보다 먼저 완료해야 한다.
- structured_task_group::wait 멤버를 호출한 후에는 다른 작업을 추가한 후 실행할 수 없다.
초간단!!! 6단계로 끝내는 태스크 사용 방법
1. ppl.h 파일을 포함합니다.
#include <ppl.h>
2. Concurrency Runtime의 네임 스페이를 선언합니다.
using namespace
Concurrency;
3. 태스크 그룹을 정의합니다.
structured_task_group structured_tasks;
4. 태스크를 정의합니다.
auto
structured_task1 = make_task([&] { Plus(arraynum1, true);
} );
5. 태스크를 태스크 그룹에 추가한 후 실행합니다.
structured_tasks.run( structured_task1 );
6. 태스크 그룹에 있는 태스크가 완료될 때까지 기다립니다.
structured_tasks.wait();
위의 순서대로 하면 태스크를 사용할 수 있습니다. 태스크 사용 참 쉽죠잉~ ^^.
참고로 여러 개의 태스크를 그룹에 추가하고 싶다면 6번 이전에 4번과 5번을 추가할 개수만큼 반복하면 됩니다.
* 4번의 Plus(arraynum1, true);는 하나의 태스크에서 실행할 함수입니다.
PPL의 태스크를 사용하면 병렬 프로그래밍을 간단한 6단계만으로 끝낼 수 있습니다. 만약 현재의 Win32 API로 이것을 구현하기 위해서는 학습에 많은 시간을 보낸 후 저수준의 API를 사용하여 구현해야 되기 때문에 구현 시간과 안정성에서 PPL의 태스크보다 손해를 봅니다.
태스크 그룹과 스레드 세이프
unstructured 와 structured 태스크 그룹의 차이가 스레드 세이프 유무의 차이라고 했는데 이 말은
unstructured 태스크 그룹은 복수의 스레드에서 호출 및 대기를 할 수 있지만 structured 태스크 그룹은 그것을 생성한 스레드에서만 호출 및 대기를 할 수 있습니다.
예를 들면 스레드 A, 스레드 B가 있는 경우 스레드 A와 B에서 태스크를 실행 후 대기를 한다면 unstructured 태스크 그룹을 사용해야하고, 오직 하나의 스레드에서만(스레드 A에서만) 태스크를 실행 후 대기를 한다면 structured 태스크 그룹을 사용합니다.
ps : 제가 8월 14일 글을 공개할 때 태스크 그룹의 스레드 세이프 특성을 잘 못 이해하여 잘못된 내용을 전달하였습니다. 그래서 오늘 글을 다시 수정하였습니다. ;;;;;;
다음부터는 틀린 글을 올리지 않도록 조심하겠습니다. ^^;;;;;;
'VC++ 10 Concurrency Runtime' 카테고리의 다른 글
Parallel Patterns Library(PPL) - parallel_for 알고리즘 (5) | 2009.09.01 |
---|---|
Parallel Patterns Library(PPL) - 병렬 알고리즘 (0) | 2009.08.19 |
양보할 줄 아는 Concurrency Runtime의 event (1) | 2009.08.07 |
Parallel Patterns Library (PPL) (1) | 2009.08.06 |
Concurrency Runtime (7) | 2009.07.30 |