[c++] C++ 스레드 풀과 작업 로깅

이번에는 C++을 사용하여 스레드 풀을 구현하고 작업 로깅을 하는 방법에 대해 알아보겠습니다.

1. C++ 스레드 풀 구현하기

C++에서 스레드 풀을 구현하는 방법에는 여러 가지가 있지만, 표준 라이브러리인 std::threadstd::future를 사용하는 방법이 일반적입니다. 아래는 간단한 예제 코드입니다.

#include <iostream>
#include <thread>
#include <vector>
#include <functional>
#include <future>

class ThreadPool {
public:
    ThreadPool(size_t numThreads) {
        for (size_t i = 0; i < numThreads; ++i) {
            threads.emplace_back([this] {
                while (true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(mutex);
                        condition.wait(lock, [this] { return stop || !tasks.empty(); });
                        if (stop && tasks.empty()) {
                            return;
                        }
                        task = std::move(tasks.front());
                        tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    template<class F, class... Args>
    auto enqueue(F&& f, Args&&... args) -> std::future<decltype(f(args...))> {
        using return_type = decltype(f(args...));
        auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
        std::future<return_type> res = task->get_future();
        {
            std::unique_lock<std::mutex> lock(mutex);
            if (stop) {
                throw std::runtime_error("enqueue on stopped ThreadPool");
            }
            tasks.emplace([task]() { (*task)(); });
        }
        condition.notify_one();
        return res;
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(mutex);
            stop = true;
        }
        condition.notify_all();
        for (std::thread& thread : threads) {
            thread.join();
        }
    }

private:
    std::vector<std::thread> threads;
    std::queue<std::function<void()>> tasks;
    std::mutex mutex;
    std::condition_variable condition;
    bool stop = false;
};

int main() {
    ThreadPool pool(4);

    std::vector<std::future<int>> results;
    for (int i = 0; i < 8; ++i) {
        results.emplace_back(
            pool.enqueue([i] {
                std::this_thread::sleep_for(std::chrono::seconds(1));
                return i * i;
            })
        );
    }

    for (auto&& result : results) {
        std::cout << result.get() << ' ';
    }
    std::cout << std::endl;

    return 0;
}

위의 코드는 스레드 풀을 구현하는 간단한 예제로, ThreadPool 클래스를 사용하여 원하는 작업을 여러 개의 스레드로 분산하여 실행할 수 있습니다.

2. 작업 로깅 구현하기

작업 로깅은 각각의 작업이 실행될 때 로그를 남기는 것을 의미합니다. 아래는 위의 예제 코드에 작업 로깅을 추가한 예제입니다.

template<class F, class... Args>
auto enqueue(F&& f, Args&&... args) -> std::future<decltype(f(args...))> {
    // 작업 시작 로깅
    std::cout << "Starting task" << std::endl;
    using return_type = decltype(f(args...));
    // ...

    // 작업 종료 로깅
    res.then([](std::future<return_type> f) {
        std::cout << "Task finished" << std::endl;
    });
    return res;
}

위의 코드에서 enqueue 함수 내에 작업 시작과 종료 시점에 로그를 남기는 부분을 추가했습니다. 이를 통해 각 작업이 언제 시작되고 종료되는지를 로깅할 수 있습니다.

3. 참고 자료

위의 내용은 C++을 사용하여 스레드 풀을 구현하고 작업 로깅하는 간단한 예제입니다. 보다 자세한 내용은 아래의 참고 자료를 참고하시기 바랍니다.

이상으로 C++ 스레드 풀과 작업 로깅에 대한 내용을 살펴보았습니다. 감사합니다!