(C++ : Concurrency) 14. parallel STL

Posted by : at

Category : Cpp


#include <iostream>
#include <algorithm>
#include <vector>
#include <thread>
#include <execution>

void foo(int n)
{
    std::cout << n << " : " << std::this_thread::get_id() << std::endl;
}

int main()
{
    std::vector<int> v{1,2,3,4,5,6,7,8,9,10};

    //std::for_each(v.begin(), v.end(), foo);
    std::for_each(std::execution::par, v.begin(), v.end(), foo);
    // std::execution::par(C++17~) : 병렬로 실행해 주세요
    // 모두 다른 thread로 실행이 된다.
}

주의사항

#include <iostream>
#include <algorithm>
#include <vector>
#include <thread>
#include <execution>
#include <mutex>
#include <chrono>
using namespace std::literals;

int main()
{
    std::vector<int> v(100, 0);

    for(int i = 1; i < 100; i++)
        v.push_back(i);

    int sum = 0;

    std::for_each(std::execution::par, v.begin(), v.end(), [&](int n) {
        sum += n;
        std::this_thread::sleep_for(1ms);
    });

    // 스레드 세이프하지않기에 5050이 나오지 않게된다.
    std::cout << sum << '\n';
}

해결해보자

int main()
{
    std::vector<int> v(100, 0);

    for(int i = 1; i < 100; i++)
        v.push_back(i);

    std::mutex m;
    int sum = 0;

    std::for_each(std::execution::par, v.begin(), v.end(), [&](int n) {
        std::lock_guard<std::mutex> lg(m);
        // mutex는 성능저하가 있다
        sum += n;
        std::this_thread::sleep_for(1ms);
    });

    std::cout << sum << '\n';
}
int main()
{
    std::vector<int> v(100, 0);

    for(int i = 1; i < 100; i++)
        v.push_back(i);

    std::atomic<int> sum = 0;

    std::for_each(std::execution::par, v.begin(), v.end(), [&](int n) {
        //sum += n;
        sum.fetch_add(n, std::memory_order_relaxed);
        std::this_thread::sleep_for(1ms);
    });

    std::cout << sum << '\n';
}

atomic smart pointer(C++20)

#include <iostream>
#include <thread>
#include <atomic>
#include <memory>

void foo()
{
    std::shared_ptr<int> ptr = std::make_shared<int>(5);

    // 값에 의한 참조로 ptr이 복사되며 또 만들어 질 것이다.
    std::thread t1([ptr]() mutable
    {
        // ptr이 새로 만들어지며 기존의 ref를 하나 줄일것인데
        // 그 ref가 동기화 될것인가??
        // 일단 스레드 세이프하다. 
        ptr = std::make_shared<int>(1);
    });

    std::thread t2([ptr]() mutable
    {
        ptr = std::make_shared<int>(2);
    });

    t1.join();
    t2.join();
}

만약 참조에 의한 캡쳐라면?

#include <iostream>
#include <thread>
#include <atomic>
#include <memory>

void foo()
{
    std::shared_ptr<int> ptr = std::make_shared<int>(5);

    std::thread t1([&ptr]() mutable
    {
        ptr = std::make_shared<int>(1);
    });

    std::thread t2([&ptr]() mutable
    {
        ptr = std::make_shared<int>(2);
    });

    // ptr이 참조값이고 두 개의 스레드가 동시에 ptr를 변경하려한다.
    // 스레드 세이프하지 못한 코드이다.

    t1.join();
    t2.join();
}

해결해보자

void foo()
{
    // atomic의 smart pointer 특수화 버전, 단, C++20부터 지원됨
    std::atomic<std::shared_ptr<int>> ptr = std::make_shared<int>(5);

    std::thread t1([&ptr]() mutable
    {
        ptr = std::make_shared<int>(1);
    });

    std::thread t2([&ptr]() mutable
    {
        ptr = std::make_shared<int>(2);
    });

    t1.join();
    t2.join();
}

About Taehyung Kim

안녕하세요? 8년차 현업 C++ 개발자 김태형이라고 합니다. 😁 C/C++을 사랑하며 다양한 사람과의 협업을 즐깁니다. ☕ 꾸준한 자기개발을 미덕이라 생각하며 노력중이며, 제가 얻은 지식을 홈페이지에 정리 중입니다. 좀 더 상세한 제 이력서 혹은 Private 프로젝트 접근 권한을 원하신다면 메일주세요. 😎

Star
Useful Links