함수 템플릿은 일일이 타입이 다르게 호출될 수 있는 함수를 하나의 정의로 일괄적으로 처리될 수 있는 기능을 제공한다. 하지만 스레드는 직접 호출하는 모양이 아니라서 타입추론이 안되기에 명시적으로 기재를 해야 하기에 그 사용방법을 알아보자.
. 테스트 코드 설명
아래 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에 대해 더 알고 싶으면
- 함수 원형
template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init ); |
(until C++20) |
- 파라미터
first, last | the range of elements to sum |
init | initial value of the sum |
- 상세 내용 확인
https://en.cppreference.com/w/cpp/algorithm/accumulate
std::accumulate - cppreference.com
(1) template< class InputIt, class T > T accumulate( InputIt first, InputIt last, T init ); (until C++20) template< class InputIt, class T > constexpr T accumulate( InputIt first, InputIt last, T init ); (since C++20) (2) template< class InputIt, class T,
en.cppreference.com
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-+
* 본 글에 예제 코드는 코드누리 교육을 받으면서 제공된 샘플코드를 활용하였습니다.
'L C++ > Concurrency' 카테고리의 다른 글
[Concurrency] race condition 예방 방법 : Mutex와 Semaphore (2) | 2023.09.26 |
---|---|
race condition : 스레드를 병렬로 그냥 동작 시키면 안 되는 이유 (0) | 2023.09.19 |
[Concurrency] 멀티(복수) 스레드를 보관하는 방법 (0) | 2023.08.15 |
[Concurrency] 주요 기능 member type / class / functions 정리 (0) | 2023.08.01 |
[Concurrency] 인자와 callable object (0) | 2023.07.24 |