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 |