멀티스레딩 프로그래밍에서 효율적인 스레드 관리는 매우 중요한 요소입니다. 기존에 사용하던 **폴링(polling)**과 이벤트(event) 기반의 스레드 생성 방식은 다음과 같은 특징을 가지고 있었습니다.
INT ThreadFunc() {
while (true) {
if (m_Flag) {
// 동작
}
Sleep(10); // CPU 사용률을 낮추기 위한 지연 시간
}
}
if (조건) {
AfxBeginThread(ThreadFunc, this, THREAD_PRIORITY_NORMAL, 0);
}
검사기 시스템에서 데이터 저장, I/O 제어, PLC 신호 체크와 같은 작업은 주기적인 확인이 필요하기 때문에 Polling 방식이 적절합니다. 하지만, 특정 기능에서는 주기적인 체크가 필요 없는 작업도 있습니다. 이런 경우에도 Polling 방식을 사용하면 불필요한 과부하가 발생하게 됩니다.
이로 인해 이벤트 기반 스레드 생성 방식을 일부 활용하였으나, 문제는 스레드 생성 비용이 발생한다는 점이었습니다.
바로 이 문제를 해결할 수 있는 것이 ThreadPool입니다.
ThreadPool은 스레드를 미리 생성해두고, 필요할 때 가져와 사용하는 방식입니다.
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
class ThreadPool {
public:
ThreadPool(size_t numThreads);
~ThreadPool();
void enqueue(std::function<void()> task);
private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queueMutex;
std::condition_variable condition;
bool stop;
};
ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this]() {
for (;;) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queueMutex);
this->condition.wait(lock, [this]() { return this->stop || !this->tasks.empty(); });
if (this->stop && this->tasks.empty())
return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
});
}
}
ThreadPool::~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (std::thread &worker : workers)
worker.join();
}
void ThreadPool::enqueue(std::function<void()> task) {
{
std::unique_lock<std::mutex> lock(queueMutex);
tasks.emplace(std::move(task));
}
condition.notify_one();
}
int main() {
ThreadPool pool(4);
for (int i = 0; i < 10; ++i) {
pool.enqueue([i]() {
std::cout << "Task " << i << " is running." << std::endl;
});
}
return 0;
}
구분Polling 방식Event 방식ThreadPool 방식
스레드 생성 | 주기적으로 체크하여 생성 | 이벤트 발생 시 생성 | 미리 생성하여 재사용 |
리소스 사용 | 과다한 CPU 사용 가능성 | 필요할 때만 리소스 사용 | 효율적인 리소스 관리 |
장점 | 주기적 작업에 적합 | 이벤트성 작업에 적합 | 모든 상황에 유연함 |
단점 | CPU 부하 발생 | 스레드 생성 비용 발생 | 초기 설정 복잡성 |
기존의 Polling과 Event 방식은 각각의 장단점이 있지만, ThreadPool을 활용하면 스레드 생성 비용을 줄이고 리소스를 효율적으로 관리할 수 있습니다.
이를 통해 검사기 시스템의 주기적 작업과 이벤트성 작업을 보다 효과적으로 관리할 수 있으며, 멀티스레딩 프로그램의 성능을 최적화할 수 있습니다.
멀티스레딩 프로그램를 개발하고 있다면 ThreadPool 사용을 고려해보세요.
C++ STL Map 사용법 및 실전 활용 (0) | 2025.01.10 |
---|