본문 바로가기
-----ETC-----/C++ 성능 최적화 및 고급 테크닉 시리즈

[C++ 성능 최적화 및 고급 테크닉] Day 20: OpenMP를 이용한 병렬 프로그래밍

by cogito21_cpp 2024. 8. 1.
반응형

OpenMP란?

OpenMP는 다중 프로세서 시스템에서 병렬 프로그래밍을 쉽게 할 수 있도록 도와주는 API입니다. OpenMP는 C, C++, Fortran에서 사용할 수 있으며, 병렬화할 코드 블록에 지시문을 추가하는 방식으로 사용됩니다.

 

OpenMP의 기본 구조

OpenMP 지시문은 #pragma를 사용하여 작성됩니다. 가장 기본적인 지시문은 #pragma omp parallel입니다.

 

기본 예제

#include <iostream>
#include <omp.h>

int main() {
    #pragma omp parallel
    {
        std::cout << "Hello, World!" << std::endl;
    }
    return 0;
}

 

이 예제에서는 #pragma omp parallel 지시문을 사용하여 병렬 영역을 정의하고, 여러 스레드에서 "Hello, World!" 메시지를 출력합니다.

 

OpenMP 지시문

1. #pragma omp parallel

병렬 영역을 정의합니다. 이 지시문 아래의 코드 블록은 병렬로 실행됩니다.

#include <iostream>
#include <omp.h>

int main() {
    #pragma omp parallel
    {
        std::cout << "Thread ID: " << omp_get_thread_num() << std::endl;
    }
    return 0;
}

 

2. #pragma omp for

반복문을 병렬로 실행합니다. #pragma omp parallel과 함께 사용됩니다.

#include <iostream>
#include <omp.h>

int main() {
    int sum = 0;
    #pragma omp parallel for
    for (int i = 0; i < 10; ++i) {
        #pragma omp atomic
        sum += i;
    }
    std::cout << "Sum: " << sum << std::endl;
    return 0;
}

 

3. #pragma omp critical

코드 블록을 한 번에 하나의 스레드만 실행하도록 합니다.

#include <iostream>
#include <omp.h>

int main() {
    int sum = 0;
    #pragma omp parallel for
    for (int i = 0; i < 10; ++i) {
        #pragma omp critical
        {
            sum += i;
        }
    }
    std::cout << "Sum: " << sum << std::endl;
    return 0;
}

 

4. #pragma omp atomic

단일 연산을 원자적으로 수행하도록 합니다.

#include <iostream>
#include <omp.h>

int main() {
    int sum = 0;
    #pragma omp parallel for
    for (int i = 0; i < 10; ++i) {
        #pragma omp atomic
        sum += i;
    }
    std::cout << "Sum: " << sum << std::endl;
    return 0;
}

 

OpenMP 환경 변수

OpenMP는 환경 변수를 통해 실행 설정을 조정할 수 있습니다.

  • OMP_NUM_THREADS: 사용할 스레드의 수를 설정합니다.
export OMP_NUM_THREADS=4

 

실습 문제

문제 1: OpenMP를 사용하여 벡터의 합 계산하기

다음 코드에서 OpenMP를 사용하여 벡터의 합을 병렬로 계산하세요.

 

main.cpp

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec(100, 1);
    int sum = 0;

    // OpenMP를 사용하여 벡터의 합을 계산하세요.
    #pragma omp parallel for
    for (int i = 0; i < vec.size(); ++i) {
        #pragma omp atomic
        sum += vec[i];
    }

    std::cout << "Sum: " << sum << std::endl;
    return 0;
}

 

해답:

main.cpp (OpenMP 적용)

#include <iostream>
#include <vector>
#include <omp.h>

int main() {
    std::vector<int> vec(100, 1);
    int sum = 0;

    // OpenMP를 사용하여 벡터의 합을 계산하세요.
    #pragma omp parallel for reduction(+:sum)
    for (int i = 0; i < vec.size(); ++i) {
        sum += vec[i];
    }

    std::cout << "Sum: " << sum << std::endl;
    return 0;
}

 

문제 2: OpenMP를 사용하여 행렬의 곱 계산하기

다음 코드에서 OpenMP를 사용하여 두 행렬의 곱을 병렬로 계산하세요.

 

main.cpp

#include <iostream>
#include <vector>

int main() {
    const int N = 3;
    std::vector<std::vector<int>> matA(N, std::vector<int>(N, 1));
    std::vector<std::vector<int>> matB(N, std::vector<int>(N, 2));
    std::vector<std::vector<int>> result(N, std::vector<int>(N, 0));

    // OpenMP를 사용하여 행렬의 곱을 계산하세요.
    #pragma omp parallel for collapse(2)
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            for (int k = 0; k < N; ++k) {
                result[i][j] += matA[i][k] * matB[k][j];
            }
        }
    }

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            std::cout << result[i][j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

 

해답:

main.cpp (OpenMP 적용)

#include <iostream>
#include <vector>
#include <omp.h>

int main() {
    const int N = 3;
    std::vector<std::vector<int>> matA(N, std::vector<int>(N, 1));
    std::vector<std::vector<int>> matB(N, std::vector<int>(N, 2));
    std::vector<std::vector<int>> result(N, std::vector<int>(N, 0));

    // OpenMP를 사용하여 행렬의 곱을 계산하세요.
    #pragma omp parallel for collapse(2)
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            for (int k = 0; k < N; ++k) {
                result[i][j] += matA[i][k] * matB[k][j];
            }
        }
    }

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            std::cout << result[i][j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

 

이제 스무 번째 날의 학습을 마쳤습니다. OpenMP의 개념과 이를 사용하여 병렬 프로그래밍을 구현하는 방법을 이해하고, 실습 문제를 통해 이를 적용하는 방법을 학습했습니다.

질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "CUDA를 이용한 GPU 프로그래밍"에 대해 학습하겠습니다.

반응형