[c++] C++에서의 고성능 멀티스레딩 패턴
C++는 고성능 멀티스레드 응용 프로그램을 개발하는 데 매우 효과적인 언어입니다. 이러한 멀티스레딩 패턴은 프로그램의 성능을 향상시키고 병렬 처리를 가능하게 합니다. 이번 글에서는 C++에서의 고성능 멀티스레딩을 위한 몇 가지 패턴을 살펴보겠습니다.
1. Thread Pool Pattern (스레드 풀 패턴)
멀티스레딩 프로그램에서 스레드를 생성하고 관리하는 것은 오버헤드를 야기할 수 있습니다. 이러한 오버헤드를 줄이고 성능을 향상시키기 위해 스레드 풀 패턴을 사용할 수 있습니다. 스레드 풀은 미리 정의된 수의 스레드를 생성하고 관리하여 작업을 병렬로 실행하는 메커니즘을 제공합니다.
예시:
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
class ThreadPool {
public:
ThreadPool(size_t numThreads) : threads(numThreads), stop(false) {
for (size_t i = 0; i < numThreads; ++i) {
threads[i] = std::thread([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queueMutex);
condition.wait(lock, [this] { return stop || !tasks.empty(); });
if (stop && tasks.empty()) {
return;
}
task = std::move(tasks.front());
tasks.pop();
}
task();
}
});
}
}
template <class F>
void enqueue(F f) {
{
std::unique_lock<std::mutex> lock(queueMutex);
tasks.emplace(f);
}
condition.notify_one();
}
~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (auto &thread : threads) {
thread.join();
}
}
private:
std::vector<std::thread> threads;
std::queue<std::function<void()>> tasks;
std::mutex queueMutex;
std::condition_variable condition;
bool stop;
};
int main() {
ThreadPool pool(4);
for (int i = 0; i < 8; ++i) {
pool.enqueue([i] {
std::cout << "Task " << i << " executed" << std::endl;
});
}
}
2. Producer-Consumer Pattern (생산자-소비자 패턴)
생산자-소비자 패턴은 데이터 공유 및 동기화 문제를 해결하기 위한 일반적인 패턴입니다. 이 패턴은 여러 생산자가 데이터를 만들고 여러 소비자가 데이터를 소비하며, 서로 독립적으로 동작하는 방식을 정의합니다.
예시:
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
class ProducerConsumer {
public:
void produce(int val) {
{
std::unique_lock<std::mutex> lock(mutex);
buffer.push(val);
}
condition.notify_one();
}
int consume() {
std::unique_lock<std::mutex> lock(mutex);
condition.wait(lock, [this] { return !buffer.empty(); });
int val = buffer.front();
buffer.pop();
return val;
}
private:
std::queue<int> buffer;
std::mutex mutex;
std::condition_variable condition;
};
int main() {
ProducerConsumer pc;
std::thread producer([&pc] {
for (int i = 0; i < 10; ++i) {
pc.produce(i);
std::cout << "Produced: " << i << std::endl;
}
});
std::thread consumer([&pc] {
for (int i = 0; i < 10; ++i) {
int val = pc.consume();
std::cout << "Consumed: " << val << std::endl;
}
});
producer.join();
consumer.join();
}
결론
C++에서 고성능 멀티스레딩을 위한 여러 패턴을 살펴보았습니다. 스레드 풀 패턴과 생산자-소비자 패턴은 병렬 처리를 향상시키는 동시에 데이터 공유 및 동기화 문제를 해결하는데 유용합니다. 이러한 패턴을 잘 활용하여 C++로 뛰어난 성능의 멀티스레딩 응용 프로그램을 개발할 수 있습니다.
관련 참고 자료:
- C++ Concurrency in Action by Anthony Williams
- The Art of Multiprocessor Programming by Maurice Herlihy and Nir Shavit