SW 그리고 아빠 엔지니어링 중...

아는 만큼 보이고, 경험해봐야 알 수 있고, 자꾸 써야 내 것이 된다.

L C++/Concurrency

[Concurrency] Function Templates(함수 템플릿)을 스레드로 실행하기

보리남편 김 주부 2023. 9. 5. 09:00
함수 템플릿은 일일이 타입이 다르게 호출될 수 있는 함수를 하나의 정의로 일괄적으로 처리될 수 있는 기능을 제공한다. 하지만 스레드는 직접 호출하는 모양이 아니라서 타입추론이 안되기에 명시적으로 기재를 해야 하기에 그 사용방법을 알아보자.

 

. 테스트 코드 설명


아래 sum() 함수는 구간의 합을 구하는 템플릿 함수이다. (템플릿 함수에 대해 자세히 알고 싶으면 여기)

template<typename IT, typename RT>
void sum(IT first, IT last, RT& result)
{
    result = std::accumulate(first, last, result);
}

그리고 std:accumulate 함수는 범위의 값을 합산하여 결과로 리턴하는 함수인데, sum() 함수는 이 함수를 이용하여 구간의 합을 구하고자 한다.

 

std:accumulate에 대해 더 알고 싶으면

 

1) 메인 스레드에서 함수 실행(스레드를 사용하지 않고 그냥 호출)


 

우선 sum()을 별도의 스레드를 사용하지 않고 구간의 합을 구해보면 다음과 같다.

전체 코드
#include <thread>
#include <numeric>
#include <vector>
#include <iostream>

constexpr std::size_t sz = 1000000;

std::vector<int> v;

void init()
{
    for (int i = 0; i < sz; ++i)
    {
        v.push_back(i);
    }
}
//----------------------------------

// 구간의 합을 구하는 함수.
template<typename IT, typename RT> 
void sum(IT first, IT last, RT& result)
{
    result = std::accumulate(first, last, result);
}
int main()
{
    init();

    // sum : v의 모든 요소의 합을 구하는 함수
    int s = 0;
    std::cout << "called the main thread !!" << std::endl;
    sum(v.begin(), v.end(), s); // 주스레드가 직접 호출

    std::cout << s << std::endl;
}
실행 결과
called the main thread !!
1783293664

 

 

2) 새로운 스레드에서 함수 실행시도 (컴파일 에러)


sum()을 메인 스레드가 아닌 새로운 스레드에서 실행시켜 보자.

//수정 코드

    // sum : v의 모든 요소의 합을 구하는 함수
    int s = 0;

//before
//    std::cout << "called the main thread !!" << std::endl;
//    sum(v.begin(), v.end(), s); // 주스레드가 직접 호출

//after
    std::cout << "called new thread !!" << std::endl;
    std::thread t(sum, v.begin(), v.end(), std::ref(s) );
                     // error
                     // sum을 직접 호출하는 모양이 아니므로 타입 추론이 안됨

 

수정된 전체 코드
#include <thread>
#include <numeric>
#include <vector>
#include <iostream>

constexpr std::size_t sz = 1000000;

std::vector<int> v;

void init()
{
    for (int i = 0; i < sz; ++i)
    {
        v.push_back(i);
    }
}
//----------------------------------

// 구간의 합을 구하는 함수.
template<typename IT, typename RT> 
void sum(IT first, IT last, RT& result)
{
    result = std::accumulate(first, last, result);
}
int main()
{
    init();

    // sum : v의 모든 요소의 합을 구하는 함수
    int s = 0;
    std::cout << "called new thread !!" << std::endl;
    std::thread t(sum, v.begin(), v.end(), std::ref(s) );
                     // error
                     // sum을 직접 호출하는 모양이 아니므로 타입 추론이 안됨

    t.join();

    std::cout << s << std::endl;
}
실행 결과
no matching function for call to 'std::thread::thread(<unresolved overloaded function type>, std::vector<int>::iterator, std::vector<int>::iterator, std::reference_wrapper<int>)'
  • 스레드의 첫 번째 인자 함수(sum) 타입을 추론하지 못해서 컴파일 에러가 발생한다.

 

3) 새로운 스레드에서 실행 되게 수정


추론할 수 없는 템플릿 매개변수는 반드시 명시적으로 지정해 주어야 합니다.

template<typename IT, typename RT>
void sum(IT first, IT last, RT& result) {
   result = std::accumulate(first, last, result);
}

선언된 sum 함수를 다시 보면 인자는 3개이지만 템플릿 매개변수 종류가 IT RT , 2개로 구성되어 있기에 sum 뒤, < > 안에 순서대로 IT와 RT에 대한 매개변수 타입을 명시해 준다.

 

//before
    //std::thread t(sum, v.begin(), v.end(), std::ref(s) ); // error

//after
    std::thread t(sum<std::vector<int>::iterator, int> , 
                    v.begin(), v.end(), std::ref(s));
  •  IT - std::vector<int>::iterator : int 타입의 벡터
  • RT - int : return 받을 타입

 

수정된 전체 코드
#include <thread>
#include <numeric>
#include <vector>
#include <iostream>

constexpr std::size_t sz = 1000000;

std::vector<int> v;

void init()
{
    for (int i = 0; i < sz; ++i)
    {
        v.push_back(i);
    }
}
//----------------------------------

// 구간의 합을 구하는 함수.
template<typename IT, typename RT> 
void sum(IT first, IT last, RT& result)
{
    result = std::accumulate(first, last, result);
}
int main()
{
    init();

    // sum : v의 모든 요소의 합을 구하는 함수
    int s = 0;
    std::cout << "called new thread !!" << std::endl;
    //std::thread t(sum, v.begin(), v.end(), std::ref(s) ); // error
    std::thread t(sum<std::vector<int>::iterator, int> , 
                    v.begin(), v.end(), std::ref(s));
    t.join();

    std::cout << s << std::endl;
}
실행 결과
called the new thread !!
1783293664

 

참조


std:accumulate : https://en.cppreference.com/w/cpp/algorithm/accumulate

템플릿 매개변수 추론 : https://junstar92.tistory.com/327#3.3-%ED%85%9C%ED%94%8C%EB%A6%BF-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98-%EC%B6%94%EB%A1%A0-+ 

 

* 본 글에 예제 코드는 코드누리 교육을 받으면서 제공된 샘플코드를 활용하였습니다.

728x90