21xrx.com
2025-03-31 17:58:01 Monday
文章检索 我的文章 写文章
C++11线程池的实现
2023-07-12 03:52:46 深夜i     13     0
C++11 线程池 实现
return this->stop || !this->tasks.empty();

随着计算机性能的提高和多核处理器的普及,多线程编程变得越来越重要。C++11引入了用于多线程编程的新特性,其中最重要的之一是std::thread类。虽然使用std::thread很容易,但在实践中,创建和销毁线程是一项开销非常大的操作。为了避免这些开销,C++11标准库还提供了std::async和std::future,可以让我们通过异步任务来利用线程。

然而,std::async只是解决了异步任务的问题,它并没有提供线程池的概念。线程池可以提高线程的利用率,因为线程的创建和销毁开销很大。使用线程池,我们可以创建一些线程,并使它们一直保持活跃状态,以便它们可以重复使用。这种方法可以大大减少线程的创建和销毁开销,从而提高程序的性能。

C++11没有提供线程池,但是我们可以使用现有的C++11特性来创建一个简单的线程池。具体来说,我们可以使用std::thread、std::function和std::queue。std::thread用于创建新线程,std::function用于绑定函数和参数,std::queue用于存储任务队列。

下面是一个简单的线程池实现:

class ThreadPool {
public:
  ThreadPool(size_t threads) {
    for (size_t i = 0; i < threads; ++i) {
      workers.emplace_back(
        [this] {
          for (;;) {
            std::function<void()> task;
            {
              std::unique_lock<std::mutex> lock(this->queue_mutex);
              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(queue_mutex);
      tasks.emplace(std::forward<F>(f));
    }
    condition.notify_one();
  }
  ~ThreadPool() {
    {
      std::unique_lock<std::mutex> lock(queue_mutex);
      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 queue_mutex;
  std::condition_variable condition;
  bool stop = false;
};

上面的代码实现了一个线程池,它提供了enqueue方法,将任务添加到任务队列中,并启动一个线程处理任务。在构造函数中,我们创建了指定数量的工作线程,并使用无限循环来处理任务。在enqueue方法中,我们将任务添加到队列中,然后通知等待队列的线程。

在析构函数中,我们设置stop标志,以便通知线程停止处理任务。然后,我们使用condition.notify_all()通知所有线程,然后等待线程结束。

使用线程池非常简单。我们可以创建ThreadPool对象,并使用enqueue方法添加任务到任务队列中。线程池将自动分配任务给一个可用的线程。

ThreadPool pool(4);
std::vector<std::future<void>> futures;
for (int i = 0; i < 8; ++i) {
  futures.emplace_back(
    pool.enqueue([i] {
      std::cout << "hello " << i << std::endl;
      std::this_thread::sleep_for(std::chrono::seconds(1));
      std::cout << "world " << i << std::endl;
    })
  );
}
for (auto& f : futures)
  f.get();

在上面的代码中,我们创建了一个ThreadPool对象,并将8个任务添加到任务队列中。每个任务都会打印一些文本,并在1秒后再次打印文本。使用std::future,我们可以等待所有任务完成后继续执行。

总之,线程池是一个非常有用的工具,可以显著提高多线程编程的性能。使用C++11的std::thread、std::function和std::queue,我们可以创建一个简单的线程池。该实现非常简单,可以轻松地扩展和优化,以满足不同的需求。

  
  

评论区