[c++] C++ 스레드 풀과 작업 취소 처리
본 포스트에서는 C++에서 스레드 풀을 구현하고, 작업 취소 처리를 하는 방법에 대해 알아봅니다.
스레드 풀의 개념
스레드 풀은 여러 작업을 처리하기 위해 미리 스레드를 생성해 놓고, 작업이 들어오면 이 스레드들을 이용해 병렬로 처리하는 기법입니다. 보통 여러 스레드를 동시에 생성하는 것보다 스레드 풀을 사용하는 것이 성능상 이점이 있습니다.
C++에서의 스레드 풀 구현
C++에서는 std::thread
를 사용하여 스레드를 생성하고 관리할 수 있습니다. 스레드 풀을 구현하기 위해서는 스레드를 미리 생성해 놓고, 작업 큐를 만들어서 스레드가 작업을 가져오도록 합니다. 또한, 스레드가 종료되지 않고 다음 작업을 처리할 수 있도록 루프를 추가하여야 합니다.
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
class ThreadPool {
public:
ThreadPool(size_t numThreads) : stop(false) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this] {
while (true) {
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();
}
});
}
}
template <class F>
void enqueue(F f) {
{
std::unique_lock<std::mutex> lock(queueMutex);
if (stop) {
throw std::runtime_error("enqueue on stopped ThreadPool");
}
tasks.emplace(f);
}
condition.notify_one();
}
~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (std::thread &worker : workers) {
worker.join();
}
}
private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queueMutex;
std::condition_variable condition;
bool stop;
};
작업 취소 처리
작업 취소는 스레드가 일정 시간동안 작업이 끝나지 않으면 해당 작업을 취소하고 다른 작업을 처리하는 기능을 말합니다. 스레드 풀에서는 각 작업이 완료되었는지 확인하는 매커니즘이 필요합니다.
#include <chrono>
#include <future>
template<typename ReturnType>
class CancellableTask
{
public:
CancellableTask(std::function<ReturnType()> f) : task(f) { }
ReturnType operator()() {
try {
return task();
}
catch (const std::future_error&) {
std::cout << "Task has been cancelled" << std::endl;
throw;
}
}
ReturnType get(std::chrono::milliseconds timeout) {
auto handle = std::async(std::launch::async, *this);
auto status = handle.wait_for(timeout);
if (status == std::future_status::timeout) {
handle.cancel();
throw std::future_error(std::future_errc::broken_promise);
}
return handle.get();
}
private:
std::function<ReturnType()> task;
};
위 예시는 C++에서 스레드 풀 및 작업 취소 처리의 기초적인 예시입니다. 추가적인 코드 및 라이브러리를 사용하여 보다 복잡하고 안전한 스레드 풀 및 작업 취소 처리를 구현할 수 있습니다.
결론
C++에서 스레드 풀을 구현하고, 작업 취소 처리를 하는 방법에 대해 알아보았습니다. 스레드 풀을 통해 병렬 작업을 처리할 때 작업 취소 처리를 유의하며 안전하고 성능적으로 효율적인 프로그램을 작성할 수 있습니다.
참고 문헌
- C++ Concurrency in Action by Anthony Williams
- C++ 스레드 문서: https://en.cppreference.com/w/cpp/thread
- C++ 동시성 프로그래밍 가이드: https://docs.microsoft.com/en-us/cpp/parallel/