> 백엔드 개발 > C++ > C++의 멀티스레딩 최적화 기술

C++의 멀티스레딩 최적화 기술

王林
풀어 주다: 2023-08-22 12:53:12
원래의
1141명이 탐색했습니다.

C++의 멀티스레딩 최적화 기술

컴퓨터 기술이 발전하고 하드웨어 성능이 향상되면서 멀티스레딩 기술은 현대 프로그래밍에 필수적인 기술이 되었습니다. C++는 많은 강력한 멀티스레딩 기술을 제공하는 고전적인 프로그래밍 언어입니다. 이 기사에서는 독자가 멀티스레딩 기술을 더 잘 적용할 수 있도록 C++의 몇 가지 멀티스레딩 최적화 기술을 소개합니다.

1. std::thread 사용

C++11에서는 멀티스레딩 기술을 표준 라이브러리에 직접 통합하는 std::thread를 도입했습니다. std::thread를 사용하여 새 스레드를 생성하는 것은 매우 간단합니다. 함수 포인터를 전달하기만 하면 됩니다. 예:

#include <thread>
#include <iostream>

void hello()
{
    std::cout << "Hello World!";
}

int main()
{
    std::thread t(hello);
    t.join();
    return 0;
}
로그인 후 복사

위 코드는 새 스레드 t를 생성하고 hello 함수를 실행하며 스레드 t가 완료될 때까지 기다립니다. 스레드 생성 및 소멸에는 일정량의 오버헤드가 필요하므로 std::thread를 합리적으로 사용해야 합니다.

2. std::async 사용

std::async는 함수를 비동기적으로 실행하고 std::future 객체를 반환할 수 있는 또 다른 편리한 멀티스레딩 기술입니다. 비동기 작업 실행을 보다 편리하게 관리하고 결과를 얻으려면 std::async를 사용하세요. 예:

#include <future>
#include <iostream>

int add(int a, int b)
{
    return a + b;
}

int main()
{
    auto async_result = std::async(add, 1, 2);
    std::cout << async_result.get();
    return 0;
}
로그인 후 복사

위 코드는 add 함수를 호출하여 1+2를 비동기적으로 계산하고 std::future 객체를 사용하여 계산 결과 획득을 관리합니다. std::async는 기본적으로 std::launch::async 전략을 사용하고 새 스레드에서 함수를 실행한다는 점에 유의해야 합니다. std::launch::deferred 전략을 사용하려면 수동으로 지정해야 합니다. 그러나 std::launch::deferred 전략을 사용하면 std::future::get()이 호출될 때만 함수가 실행되므로 사례별로 선택해야 합니다.

3. std::condition_variable을 사용하세요

멀티 스레드 프로그래밍에서는 스레드 간에 통신 및 동기화가 수행되어야 하며, std::condition_variable은 이러한 목적을 매우 잘 달성할 수 있습니다. std::condition_variable을 사용하면 한 스레드가 다른 스레드의 특정 조건이 true가 될 때까지 기다릴 수 있으므로 스레드 간 동기화가 달성됩니다. 예:

#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>

std::mutex mutex;
std::condition_variable cv;
bool ready = false;

void producer()
{
    std::unique_lock<std::mutex> lock(mutex);
    // wait for the condition to become true
    cv.wait(lock, [] { return ready; });
    std::cout << "Producer done." << std::endl;
}

void consumer()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    ready = true;
    std::cout << "Consumer done." << std::endl;
    cv.notify_one();
}

int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
    return 0;
}
로그인 후 복사

위 코드는 두 개의 스레드 t1과 t2를 생성합니다. 여기서 t1은 조건 변수가 true가 될 때까지 기다리고, t2는 1초 동안 기다린 후 조건 변수를 true로 설정하고 t1에 알립니다. 여러 스레드가 동시에 조건 변수에 액세스하는 것을 방지하려면 std::condition_variable을 std::mutex와 함께 사용해야 합니다.

4. 스레드 풀 사용

생성하고 실행해야 하는 단기 작업이 많은 경우 프로그램 성능을 향상시키기 위해 스레드 풀을 사용하는 경우가 많습니다. 스레드 풀은 일정 수의 스레드를 유지하고 작업 할당 및 실행을 관리합니다. 스레드 풀을 사용하면 스레드를 자주 생성하고 삭제하는 추가 오버헤드를 방지하는 동시에 멀티 코어 CPU를 최대한 활용할 수 있습니다. 예:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <queue>
#include <functional>

class ThreadPool
{
public:
    ThreadPool(std::size_t numThreads = std::thread::hardware_concurrency())
    {
        for (std::size_t i = 0; i < numThreads; ++i)
        {
            pool.emplace_back([this] {
                while (!stop)
                {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock{ mutex };
                        condition.wait(lock, [this] { return stop || !tasks.empty(); });
                        if (stop && tasks.empty()) return;
                        task = std::move(tasks.front());
                        tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    ~ThreadPool()
    {
        {
            std::unique_lock<std::mutex> lock{ mutex };
            stop = true;
        }
        condition.notify_all();
        for (auto& worker : pool)
        {
            worker.join();
        }
    }

    template <typename F, typename... Args>
    auto enqueue(F&& f, Args&&... args)
        -> std::future<typename std::result_of<F(Args...)>::type>
    {
        using return_type = typename std::result_of<F(Args...)>::type;
        auto task = std::make_shared<std::packaged_task<return_type()>>(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...));
        std::future<return_type> future = task->get_future();
        {
            std::unique_lock<std::mutex> lock{ mutex };
            if (stop) throw std::runtime_error("enqueue on stopped ThreadPool");
            tasks.emplace([task](){ (*task)(); });
        }
        condition.notify_one();
        return future;
    }

private:
    std::vector<std::thread> pool;
    std::queue<std::function<void()>> tasks;
    std::mutex mutex;
    std::condition_variable condition;
    bool stop = false;
};

void hello()
{
    std::cout << "Hello World!" << std::endl;
}

int add(int a, int b)
{
    return a + b;
}

int main()
{
    {
        ThreadPool pool;
        auto f1 = pool.enqueue(hello);
        auto f2 = pool.enqueue(add, 1, 2);
        std::cout << f2.get() << std::endl;
    }
    return 0;
}
로그인 후 복사

위 코드는 여러 스레드와 작업 대기열을 포함하는 ThreadPool 클래스를 정의합니다. 스레드 풀은 작업 대기열에서 작업을 계속 가져와 대기열이 비어 있거나 스레드 풀이 중지될 때까지 실행합니다. ThreadPool::enqueue 메소드를 사용하여 작업 큐에 작업을 추가하고 std::future 객체를 반환하여 작업 실행 결과를 관리합니다.

일반적으로 C++는 개발자가 멀티 코어 CPU의 성능을 활용하고 스레드와 작업을 보다 유연하게 관리할 수 있도록 다양한 멀티 스레딩 기술을 제공합니다. 개발자는 프로그램 성능을 최적화하기 위해 이러한 기술을 적절하게 사용해야 합니다.

위 내용은 C++의 멀티스레딩 최적화 기술의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿