返回

C++学习记录:从一个小线程池源码看C++11新特性的优雅使用

后端

最近抽空学习一些感兴趣的源码,这次学习一个小而美的C++11线程池源码。核心代码很简单,就是下面这不到一百行。但是其中使用了很多新C++11的新东西,写的非常优雅,有很多可以学习的地方。

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>

class ThreadPool {
public:
    ThreadPool(int num_threads) : num_threads_(num_threads) {
        for (int i = 0; i < num_threads_; ++i) {
            threads_.emplace_back([this] {
                while (true) {
                    std::unique_lock<std::mutex> lock(mutex_);
                    if (tasks_.empty()) {
                        cv_.wait(lock);
                    }
                    auto task = std::move(tasks_.front());
                    tasks_.pop();
                    lock.unlock();
                    task();
                }
            });
        }
    }

    ~ThreadPool() {
        {
            std::lock_guard<std::mutex> lock(mutex_);
            stop_ = true;
            cv_.notify_all();
        }
        for (auto& thread : threads_) {
            thread.join();
        }
    }

    void addTask(std::function<void()> task) {
        std::lock_guard<std::mutex> lock(mutex_);
        tasks_.push(std::move(task));
        cv_.notify_one();
    }

private:
    std::vector<std::thread> threads_;
    std::mutex mutex_;
    std::condition_variable cv_;
    std::queue<std::function<void()>> tasks_;
    bool stop_ = false;
    int num_threads_;
};

int main() {
    ThreadPool pool(4);
    for (int i = 0; i < 10; ++i) {
        pool.addTask([i] {
            std::cout << "Task " << i << " is running." << std::endl;
        });
    }

    return 0;
}

这个线程池源码的核心思想很简单,就是使用一个队列来存储任务,然后使用多个线程来处理队列中的任务。当队列为空时,线程会等待,当有任务加入队列时,线程会唤醒并执行任务。

这个源码中使用了许多新C++11的新特性,包括:

  • 智能指针:使用std::unique_lock来管理互斥量,这种智能指针会在析构时自动解锁互斥量,非常方便。
  • 标准库:使用了std::threadstd::mutexstd::condition_variable等标准库中的并发原语。
  • 并发:使用了多个线程来并行执行任务,提高了程序的性能。
  • 互斥量:使用了std::mutex来保护共享数据,防止多个线程同时访问共享数据。

这个线程池源码写的非常优雅,代码简洁易懂,而且性能也非常不错。如果你想学习C++11的新特性,或者想学习如何编写一个线程池,这个源码是一个非常好的参考。

除了上述优点之外,这个线程池源码还有以下一些特点:

  • 可以通过构造函数指定线程池的大小,这样可以根据实际需要来调整线程池的性能。
  • 线程池会自动回收空闲的线程,这样可以节省系统资源。
  • 线程池可以方便地添加任务,只需要调用addTask()方法即可。

总之,这个线程池源码是一个非常优秀的作品,值得我们学习和借鉴。