이전 정리글은
2021.12.28 - [프로그래밍/Parallel Programming] - 병렬 프로그래밍 Parallel Programming - parallel_sort
오늘은 7번째 정리시간이다. 오늘은 무엇에 대해서 정리해볼까.? 오늘은 PPL 에서 제공하는 컨테이너에 대해서 정리해보자. 먼저 알아볼 것은 vector 에 대해서 알아보자.
concurrency::concurrent_vector
우리가 알고 있는 STL vector 와 동일한 것이다. 하지만 차이가 있다.
병행 프로그래밍에서 사용할 수 있는 컨테이너이기에 제공하는 몇개의 함수에 대해서 thread-safe 를 보장한다. 그럼 어떤 함수들이 thread-safe 한지 알아보자.
함수 | thread-safe | 함수 | thread-safe | 함수 | thread-safe | 함수 | thread-safe |
resize | FALSE | assign | FALSE | reserve | FALSE | clear | FALSE |
operator= | FALSE | empty | TRUE | size | TRUE | rend | TRUE |
max_size | TRUE | grow_to_at_least | TRUE | grow_by | TRUE | rbegin | TRUE |
at | TRUE | push_back | TRUE | back | TRUE | end | TRUE |
front | TRUE | operator[] | TRUE | capacity | TRUE |
위의 표를 보면 thread-safe 한 함수를 알 수 있다. 랜덤 액세스 후 대입 연산이 안되는 것은 아쉽긴 하다.
또 STL vector 와 다른 점이 있는데 원소 추가 작업 시 move 가 적용되지 않는 것이다. 그리고 원소를 연속된 공간에 저장하지 않으므로 메모리 번지 후 가감 연산을 통해 접근 할 수 없다.
자 코드를 보자.
#include <ppl.h>
#include <concurrent_vector.h>
#include <iostream>
using namespace std;
int _tmain()
{
concurrency::concurrent_vector<int> vecConcurrent;
concurrency::parallel_invoke(
[&]{
for(int i=0;i<100;i++)
{
vecConcurrent.push_back(i);
}
},
[&]{
for(int i=100;i<200;i++){
vecConcurrent.push_back(i);
}
}
);
for(int i=0;i<200;i++){
wcout << L"index[" << i << L"] : " << vecConcurrent.at(i) << endl;
}
return 0;
}
위 코드를 실행해보면 vector 에 값이 잘 들어가지는 것을 확인할 수 있다.
concurrency::concurrent_queue
역시 vector 와 마찬가지로 STL queue 와 같은 것이다. 차이점도 thread-safe 한 함수 제공과 특성이 조금 다르다는 것이다.
thread-safe 한 함수는 다음과 같다.
함수 | thread-safe | 함수 | thread-safe | 함수 | thread-safe | 함수 | thread-safe |
operator-> | FALSE | operator++ | FALSE | operator* | FALSE | rend | FALSE |
unsafe_begin | FALSE | unsafe_end | FALSE | clear | FALSE | empty | TRUE |
push | TRUE | try_pop | TRUE |
concurrent_queue 는 iterator 를 제공하지만 thread-safe 하지는 않다. 코드를 보자 다음 코드는 오브젝트 풀의 push를 발췌한 것이다.
template<typename T>
class NzOPool {
public:
....
T* Pop() {
T* pRet = nullptr;
if (m_queObjects.try_pop(pRet) == false) {
Trace(_T("obj pool try pop error new return..\n"));
pRet = new T();
++m_nMaxSize;
}
return pRet;
}
void Push(T* pObj) {
m_queObjects.push(pObj);
}
private:
concurrency::concurrent_queue<T*> m_queObjects;
};
다음은 병렬 객체에 대해서 정리해보자. 병렬 객체의 쓰임새는 여러 스레드에서 객체를 공유하고자 할때 유용하다.
concurrency::combinable
역시 코드를 보자.!!!!
#include <ppl.h>
#include <array>
#include <numeric>
#include <iostream>
using namespace std;
bool isPrime(int value)
{
if( value < 2) return false;
for(int i=2;i < value; i++){
if( (value % i) == 0) return false;
}
return true;
}
int main(){
int totalSum = 0;
array<int, 100000> nums;
concurrency::combinable<int> combine;
iota(begin(nums), end(nums), 0);
concurrency::parallel_for_each(begin(nums), end(nums), [&](int i){
combine.local() += (isPrime(i) ? i : 0 );
}
);
totalSum = combine.combine(plus<int>());
/*
아래와 같이도 가능
totalSum = 0;
combine.combine_each(
[&](int n){
totalSum += n;
}
);
*/
wcout << L"Total value : " << totalSum << endl;
return 0;
}
위 코드를 보게되면 combinable local() 함수를 사용하고 있는데 해당 함수는 스레드별로 독립적인 객체를 반환한다. 스레드별 독립된 변수에 각 스레드 별 값을 더하고 parallel_for_each 함수가 완료되면 combinable 의 combine 함수를 통하여 각각의 값에 대한 연산을 처리할 수 있다. 해당 객체를 활용하면 추가적으로 우리가 동기화 객체를 사용하지 않아도 스레드간 공유할 수 있는 객체를 생성할 수 있다.
막간으로 기본 타입이 아닌 클래스를 사용할 경우도 한번 보자.
concurrency::combinable<Base::BoundBox3d> bbs;
concurrency::parallel_for_each(_Points.begin(), _Points.end(),
[this, &bbs](const value_type& value) {
Base::Vector3d vertd(value.x, value.y, value.z);
bbs.local().Add(this->_Mtrx * vertd);
}
);
bbs.combine_each([&bnd](const Base::BoundBox3d& lbb) {
bnd.Add(lbb);
});
짜잔~! 클래스를 사용할 때도 크게 다르지 않다. 범위가 크고 복잡한 연산을 대상으로 할 때 동기화 객체를 따로 작성하여 수행하는 것보다 성능이 좋다고 한다.
다음 정리글은
2022.01.03 - [프로그래밍/Parallel Programming] - 병렬 프로그래밍 Parallel Programming - concurrent_unordered_map
'프로그래밍 > Parallel Programming' 카테고리의 다른 글
병렬 프로그래밍 Parallel Programming - cancellation_token (0) | 2022.01.03 |
---|---|
병렬 프로그래밍 Parallel Programming - concurrent_unordered_map (0) | 2022.01.03 |
병렬 프로그래밍 Parallel Programming - parallel_sort (0) | 2021.12.28 |
병렬 프로그래밍 Parallel Programming - parallel_invoke (0) | 2021.12.26 |
병렬 프로그래밍 Parallel Programming - parallel_for (0) | 2021.12.22 |