스레드 풀(Thread Pool)

김 무무 ㅣ 2024. 10. 17. 11:17

1. 스레드 풀이란 

미리 생성된 여러 개의 작업자 스레드를 관리하는 소프트웨어 디자인 패턴

다수의 작은 태스크를 효율적으로 처리하기 위해 사용된다.

 

특징:

  - 성능 향상 : 스레드 생성 및 소멸 비용을 줄인다.

  - 리소스 관리 : 동시에 실행되는 스레드 수를 제한하여 시스템 리소스를 효율적으로 사용한다.

  - 안정성 : 과도한 스레드 생성으로 인한 시스템 부하를 방지한다.

  - 재사용성 : 스레드를 재사용하여 효율성을 높인다.

 

2. 스레드 풀 구현

 

구현 순서:

1) 작업 큐 생성

2) 스레드 풀 생성

3) 작업 제출 메커니즘 구현

4) 결과 반환 메커니즘 구현

 

ex)

#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;

class ThreadPool {
private:
    vector<thread> threads;
    queue<int> tasks;
    mutex mutex;
    condition_variable condition;
    bool stop = false;

public:
    // 지정된 수의 WorkerThread 생성
    ThreadPool(int threadsCount) {
        for (int i = 0; i < threadsCount; i++) {
            threads.emplace_back([this] { this->WorkerFunction(); });
        }
    }
    // 정수ID로된 작업을 스레드 풀에 추가
    void AddTask(int task_id) {
        lock_guard<std::mutex> lock(mutex);
        tasks.push(task_id);
        condition.notify_one();
    }

    ~ThreadPool() {
        {
            lock_guard<std::mutex> lock(mutex);
            stop = true;
        }
        condition.notify_all();
        for (auto& thread : threads) {
            thread.join();
        }
    }

private:
    void WorkerFunction() {
        while (true) {
            int task_id;

            {
                unique_lock<std::mutex> lock(mutex);

                condition.wait(lock, [this] { return stop || !tasks.empty(); });
                if (stop && tasks.empty()) return;

                task_id = tasks.front();
                tasks.pop();
            }
            cout << "Thread : " << this_thread::get_id() << " 작업 : " << task_id << endl;
            // 작업
            this_thread::sleep_for(chrono::seconds(1));
        }
    }
};

int main() {
    ThreadPool pool(3);

    for (int i = 1; i <= 10; i++)
        pool.AddTask(i);

    this_thread::sleep_for(chrono::seconds(7));
}

 

3개의 스레드를 가진 스레드 풀을 생성하고, 10개의 작업을 추가해 어떤 스레드가 어떤 작업을 하는지를 출력한다.

 

 

3. 사용 시 주의사항

  - 데드락 방지 : 순환 의존성이 있는 작업을 제출하지 않도록 주의

  - 작업 크기 : 너무 작은 작업은 오버헤드를 증가시키고, 너무 큰 작업은 병렬성을 저하시킴

  - 예외 처리 : 작업 내에서 발생한 예외를 적절히 처리해야 함

  - 종료 처리 : 풀의 안전한 종료를 보장해야 함

'멀티스레딩' 카테고리의 다른 글

고급 동기화 기법  (1) 2024.10.16
Condition Variable  (0) 2024.10.16
C++ 비동기 프로그래밍  (0) 2024.10.15
스핀락(Spinlock)  (0) 2024.10.12
데드락(Deadlock)  (1) 2024.10.07