수색…


소개

이 주제에서는 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
...


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow