[c++] C++ 스레드 풀과 작업 경쟁 조건 방지

이번에는 C++를 사용하여 스레드 풀(Thread Pool)을 구현하고, 작업 경쟁 조건(Race Condition)을 방지하는 방법에 대해 알아보겠습니다.

스레드 풀이란?

스레드 풀은 일반적으로 여러 작업을 처리하기 위한 스레드의 그룹으로, 스레드를 미리 생성해 놓고 작업이 필요할 때마다 이를 사용합니다. 이를 통해 스레드 생성 및 제거로 인한 오버헤드를 줄일 수 있습니다.

C++ 스레드 풀 구현

C++11 이후부터는 std::thread 라이브러리를 사용하여 스레드를 생성하고 관리할 수 있습니다. 따라서, 간단한 스레드 풀을 구현하기 위해서는 이를 활용할 수 있습니다. 또한 std::mutex를 사용하여 스레드 간의 작업 경쟁 조건을 방지할 수 있습니다.

아래는 간단한 C++ 스레드 풀의 예제 코드입니다.

#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&& task) {
        {
            std::unique_lock<std::mutex> lock(queueMutex);
            tasks.emplace(std::forward<F>(task));
        }
        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;
};

int main() {
    ThreadPool pool(4);
    for (int i = 0; i < 8; ++i) {
        pool.enqueue([i] {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            std::cout << "Task " << i << " completed" << std::endl;
        });
    }
    return 0;
}

위의 예제 코드에서 ThreadPool 클래스는 스레드 풀을 나타내며, enqueue 메서드를 사용하여 작업을 추가할 수 있습니다. 작업은 내부적으로 큐에 추가되고, 스레드 풀의 스레드들이 작업을 가져와 처리합니다.

작업 경쟁 조건 방지

C++에서는 std::mutex를 사용하여 여러 스레드가 공유하는 리소스에 대한 접근을 동기화할 수 있습니다. 위의 예제에서는 큐에 대한 접근을 보호하기 위해 std::mutexstd::condition_variable을 활용하여 작업 경쟁 조건을 방지하였습니다.

작업 경쟁 조건은 멀티 스레드 환경에서 공유 리소스에 대한 접근이 제어되지 않을 때 발생할 수 있는 문제입니다. 이를 방지하기 위해 스레드 간의 접근을 동기화하고, 상호 배제를 통해 안전한 작업 수행을 보장할 수 있습니다.

이제 C++로 스레드 풀을 구현하고, 작업 경쟁 조건을 방지하는 방법에 대해 알아보았습니다. 이를 활용하여 멀티 스레드 환경에서 안전하고 효율적인 작업 처리를 구현할 수 있습니다.