C++
OpenMP로 동시성
수색…
소개
이 주제에서는 OpenMP를 사용하는 C ++의 동시성에 대한 기본 사항을 다룹니다. OpenMP는 OpenMP 태그 에 자세히 설명되어 있습니다.
병렬성 또는 동시성은 동시에 코드 실행을 의미합니다.
비고
OpenMP는 빌트인 컴파일러 기능이므로 특별한 헤더 나 라이브러리가 필요하지 않습니다. 그러나 omp_get_thread_num()
과 같은 OpenMP API 함수를 사용하는 경우 omp.h
와 해당 라이브러리를 포함 omp.h
합니다.
컴파일하는 동안 OpenMP 옵션을 사용하지 않으면 OpenMP pragma
문이 무시됩니다. 컴파일러 설명서에서 컴파일러 옵션을 참조 할 수 있습니다.
- GCC는
-fopenmp
사용-fopenmp
- Clang은
-fopenmp
사용-fopenmp
- MSVC는
/openmp
사용합니다.
OpenMP : 병렬 섹션
이 예제는 코드 섹션을 병렬로 실행하는 기본 사항을 보여줍니다.
OpenMP는 내장 컴파일러 기능이므로 라이브러리를 포함하지 않고 지원되는 모든 컴파일러에서 작동합니다. openMP API 기능을 사용하려면 omp.h
를 포함 할 수 있습니다.
샘플 코드
std::cout << "begin ";
// This pragma statement hints the compiler that the
// contents within the { } are to be executed in as
// parallel sections using openMP, the compiler will
// generate this chunk of code for parallel execution
#pragma omp parallel sections
{
// This pragma statement hints the compiler that
// this is a section that can be executed in parallel
// with other section, a single section will be executed
// by a single thread.
// Note that it is "section" as opposed to "sections" above
#pragma omp section
{
std::cout << "hello " << std::endl;
/** Do something **/
}
#pragma omp section
{
std::cout << "world " << std::endl;
/** Do something **/
}
}
// This line will not be executed until all the
// sections defined above terminates
std::cout << "end" << std::endl;
출력
이 예제는 가능한 2 개의 출력을 생성하며 운영 체제 및 하드웨어에 따라 다릅니다. 출력은 또한 그러한 구현으로 인해 발생할 수있는 경쟁 조건 문제를 보여줍니다.
출력 A | 출력 B |
---|---|
안녕 끝내 세계 끝이다. | 세계를 끝내라. |
OpenMP : 병렬 섹션
이 예제는 코드 덩어리를 병렬로 실행하는 방법을 보여줍니다.
std::cout << "begin ";
// Start of parallel sections
#pragma omp parallel sections
{
// Execute these sections in parallel
#pragma omp section
{
... do something ...
std::cout << "hello ";
}
#pragma omp section
{
... do something ...
std::cout << "world ";
}
#pragma omp section
{
... do something ...
std::cout << "forever ";
}
}
// end of parallel sections
std::cout << "end";
산출
- 안녕 세상을 영원히 끝내라.
- 세상을 영원히 끝내라.
- 안녕, 영원히 세계 끝.
- 영원히 안녕하세요 세상 끝을 시작합니다.
실행 순서가 보장되지 않으므로 위 출력 중 하나를 관찰 할 수 있습니다.
OpenMP : 병렬 For 루프
이 예에서는 루프를 동일한 부분으로 나누고 병렬로 실행하는 방법을 보여줍니다.
// Splits element vector into element.size() / Thread Qty
// and allocate that range for each thread.
#pragma omp parallel for
for (size_t i = 0; i < element.size(); ++i)
element[i] = ...
// Example Allocation (100 element per thread)
// Thread 1 : 0 ~ 99
// Thread 2 : 100 ~ 199
// Thread 2 : 200 ~ 299
// ...
// Continue process
// Only when all threads completed their allocated
// loop job
...
* 할당 된 범위 인덱스가 자동으로 업데이트되지 않으므로 병렬 루프에 사용되는 벡터의 크기를 수정하지 않도록 특히주의하십시오.
OpenMP : 병렬 수집 / 축소
이 예제는 std::vector
와 OpenMP를 사용하여 축소 또는 수집을 수행하는 개념을 설명합니다.
여러 개의 스레드가 우리가 물건을 생성하는 데 도움이되는 시나리오가 있다고 가정 할 때, int
는 단순함을 위해 여기에 사용되며 다른 데이터 유형으로 대체 될 수 있습니다.
이는 세그먼트 오류 또는 메모리 액세스 위반을 피하기 위해 슬레이브의 결과를 병합해야하고 라이브러리 또는 사용자 정의 동기화 컨테이너 라이브러리를 사용하지 않으려 고 할 때 특히 유용합니다.
// The Master vector
// We want a vector of results gathered from slave threads
std::vector<int> Master;
// Hint the compiler to parallelize this { } of code
// with all available threads (usually the same as logical processor qty)
#pragma omp parallel
{
// In this area, you can write any code you want for each
// slave thread, in this case a vector to hold each of their results
// We don't have to worry about how many threads were spawn or if we need
// to repeat this declaration or not.
std::vector<int> Slave;
// Tell the compiler to use all threads allocated for this parallel region
// to perform this loop in parts. Actual load appx = 1000000 / Thread Qty
// The nowait keyword tells the compiler that the slave threads don't
// have to wait for all other slaves to finish this for loop job
#pragma omp for nowait
for (size_t i = 0; i < 1000000; ++i
{
/* Do something */
....
Slave.push_back(...);
}
// Slaves that finished their part of the job
// will perform this thread by thread one at a time
// critical section ensures that only 0 or 1 thread performs
// the { } at any time
#pragma omp critical
{
// Merge slave into master
// use move iterators instead, avoid copy unless
// you want to use it for something else after this section
Master.insert(Master.end(),
std::make_move_iterator(Slave.begin()),
std::make_move_iterator(Slave.end()));
}
}
// Have fun with Master vector
...