프로그래밍/Parallel Programming

병렬 프로그래밍 Parallel Programming - task

nanze 2021. 12. 17. 23:09
반응형

 병렬 프로그램이란 무엇인가 ? 병렬... 우리나라 말에는 한자가 섞여있어서 쉽지 않다. 사전에서 찾아보면 竝列 이런 글자를 쓰고 있고 단어 하나 하나 풀이해보면 나란히 '병', 벌일 '렬' 해서 나란히 벌려놓다 모 이런 뜻이다. 솔직히 개인적으로 병렬 프로그래밍의 병렬이 그 의미를 그냥 갖다 붙여놓은 느낌이다. 실제 의미는 여러 개 프로세스를 이용하여 동시에 작업을 처리하는 프로그래밍 기법인데 ... 

 아무튼 병렬 프로그래밍이란 여러 프로세스를 이용하여 동시에 작업을 처리하는 프로그래밍 기법을 일컫는다. 내가 이해한 바로는 ;;

 

 이런 병령 프로그래밍을 위해서 위대하신 분들이 편리하게 구현할 수 있도록 라이브러리들을 만들어 놓았는데 그 중 하나는 PPL 이라는 것이다. 나는 게임을 많이해서 그런지 PPL 하고 떠오른 것은 people 이었다. 음 대규모 전투 멀티 게임해서 보통 사람들을 일컬어 ppl 이라고 들해서;; 

PPL 은 Parallel Patterns Library 의 약자이다. 이러한 라이브러리는 c++ 11 이상에서 지원되는 것으로 안다. 

 

task class

 우선  task 클래스 에 대해서 알아보자.! 

 task 클래스는 말 그대로 업무, 작업을 의미한다. 병렬 프로그래밍에서 하나 하나의 작업 단위를 대표하는 클래스로 생각하면 될 것 같다. PPL 의 사용하기 위해서는 가장 기본이 되는 클래스라고들 한다. 

 다음은 해당 클래스를 사용하기 위한 예시이다.

#include <ppltasks.h>
#include <iostream>

int _tmain()
{
    concurrency::task<int> task_one(
    	[](){
        	return 1;
    	}
    );
    
    task_one.wait();
    
    wcout << L"Task one return " << endl;
    wcout << task_one.get() << endl;
    return 0;
}

위 코드를 보면 task 를 생성하고 있는 부분을 알 수 있다. task 를 생성하기 위해 템플릿 안에 int를 명시하였는데 해당 의미는 task 가 int 형을 반환하는 것을 말하며 전달된 인자의 람다 함수는 task 가 하는 작업의 본체인 것이다. 음 task 가 처리해야 하는 업무인 것!!

 task를 생성하는 방법은 위의 예제 코드 말고도 다양한 방법이 존재한다. 다음은 위와 동일한 수행을 한다.~

#include <ppltasks.h>
#include <iostream>

int _tmain()
{
    auto task_one = concurrency::create_task(
    	[]()-> int {
        	return 1;
    	}
    );
    
    task_one.wait();
    
    wcout << L"Task one return " << endl;
    wcout << task_one.get() << endl;
    return 0;
}

 다음은 이러한 예를 한번 알아보자.~!  보통 현실에서도 작업은 동시에 일어나기도 하고 어떤 작업은 순차적으로 일어나기도 한다. 이런 경우를 표현하기 위해서는 어떻게 할까 ? 

#include <ppltasks.h>
#include <iostream>

int _tmain()
{
    auto taskone = concurrency::create_task([]()->int
    	{
        	return 1;
    	}
    );
    
    taskone.then(
    	[](int preResult){
        	wcout << preResult << endl;
        }
    ).wait();
}

 위 코드를 보면 then 함수에 집중하자. ㅋ task 클래스의 then 함수는 작업과 작업 간 연결을 해준다. 위 코드는 taskone 작업이 1을 반환하고 그 이후 해당 값을 출력하는 작업이 연결된 것이다. then 은 task를 반환하는 것도 잊지말자. 그리고 중요한 것은 이전 작업의 반환 타입과 연결된 작업의 함수 인자의 타입은 반드시 동일해야 한다.~!!!! 여기서 이렇게 task 연결 시 이전 task의 반환 타입과 다음 task의 함수 인자 타입이 같아야 하는 것을 value based coninuations 라고 부른다고 합니다. 말이 어렵다.ㅋ 또한 전자와 다르게 자식 task 가 이전 task 타입을 인자로 받을  수 있는데 이것을 task based coninuations 라고 한단다. 모 아무튼 두가지 방식을 기억하면 될 듯한다. 다음은 코드는 task based continuations 이다.

#include <ppltasks.h>
#include <iostream>

int _tmain()
{
    auto taskone = concurrency::create_task([]()->int
    	{
        	return 1;
    	}
    );
    
    taskone.then(
    	[](concurrency::task<int> pretask){
        	wcout << pretask.get() << endl;
        }
    ).wait();
}

 위 코드는 이전 코드와 동일하다. ~!!!! 다음 예제는 task 연결을 다시 한번 보여준다.~~

#include <ppltasks.h>
#include <iostream>

int _tmain()
{
    int nres = 0;
    auto sub = [](int n){ return n-1;};
    auto inc = [](int n){ return n+1;};
    auto taskone = concurrency::create_task([]()->int
    	{
        	return 1;
    	}
    );
    
    nres = taskone.then(sub).then(sub).then(sub).then(inc).get();
    wcout << L"result : " << nres << endl;
}

 이어지는 정리는 다음 장에서 ㅜㅜ;

 

다음 정리글은

2021.12.18 - [프로그래밍/Parallel Programming] - 병렬 프로그래밍 Parallel Programming - when_all, when_any

반응형