21xrx.com
2024-12-23 01:42:53 Monday
登录
文章检索 我的文章 写文章
C++实现手写线程池
2023-07-05 09:00:45 深夜i     --     --
C++ 手写线程池 实现
return !tasks_.empty() || stop_;

随着多核心处理器的普及,多线程编程也越来越重要。为了能够更好的利用 CPU 资源,减少线程切换的开销,线程池成为了一种高效的多线程编程方式。本文将介绍如何使用 C++ 实现一个手写线程池。

线程池的基本原理

线程池是一种将多个任务放入队列中,由一组线程来共享执行这些任务的方式。线程池的主要作用是:降低线程的创建、销毁以及上下文切换的开销,提高线程的利用率。线程池包含一个任务队列和一组工作线程。它的基本原理是:当一个任务到来时,线程池首先会在任务队列中添加这个任务。如果线程池中有空闲的工作线程,则会分配一个工作线程来执行这个任务。如果没有空闲线程,则等待任务队列中有任务后再分配工作线程。

线程池的实现

接下来我们开始实现线程池。首先我们需要定义一个线程池类。线程池类中包含一个任务队列和一组工作线程。任务队列中使用 STL 中的队列来实现。工作线程使用 C++ 中的 std::thread 来实现。代码如下:


#include <thread>

#include <vector>

#include <queue>

#include <functional>

#include <mutex>

#include <condition_variable>

class ThreadPool {

public:

  ThreadPool(int num_threads);

  ~ThreadPool();

  void AddTask(std::function<void()> task);

private:

  void Worker();

  std::vector<std::thread> workers_;

  std::queue<std::function<void()>> tasks_;

  std::mutex queue_mutex_;

  std::condition_variable condition_;

  bool stop_;

};

ThreadPool::ThreadPool(int num_threads) : stop_(false) {

  for (int i = 0; i < num_threads; ++i) {

    workers_.emplace_back([this] { Worker(); });

  }

}

ThreadPool::~ThreadPool() {

  {

    std::unique_lock<std::mutex> lock(queue_mutex_);

    stop_ = true;

  }

  condition_.notify_all();

  for (std::thread &worker : workers_) {

    worker.join();

  }

}

void ThreadPool::AddTask(std::function<void()> task) {

  {

    std::unique_lock<std::mutex> lock(queue_mutex_);

    tasks_.emplace(task);

  }

  condition_.notify_one();

}

void ThreadPool::Worker() {

  while (!stop_) {

    std::function<void()> task;

    {

      std::unique_lock<std::mutex> lock(queue_mutex_);

      condition_.wait(lock, [this]{ return !tasks_.empty() || stop_; });

      if (stop_ && tasks_.empty())

        return;

      

      task = tasks_.front();

      tasks_.pop();

    }

    task();

  }

}

上面代码中,我们使用了 mutex 和 condition_variable 来实现线程间的同步。Worker() 函数是工作线程的执行函数,该函数会不断地从任务队列中取出任务并执行。

ThreadPool 类包含了一个 AddTask() 函数,用于将任务添加到任务队列中。在 AddTask() 中,我们首先使用 queue_mutex_ 互斥锁来保证队列的线程安全。然后将任务添加到队列中,接着使用 condition_variable 来通知一个空闲的线程来执行任务。

线程池的使用

使用线程池十分简单。只需要实例化一个 ThreadPool 对象,然后调用其 AddTask() 函数分配任务即可:


#include "thread_pool.h"

int main() {

  ThreadPool thread_pool(4);

  for (int i = 0; i < 100; ++i) {

    thread_pool.AddTask([]

      // 处理任务的逻辑

    );

  }

  return 0;

}

在上面的代码中,我们创建了一个含有 4 个工作线程的线程池,并将 100 个任务添加到任务队列中。由于线程池中有 4 个工作线程,因此最多只会有 4 个任务同时被执行。

总结

线程池是一种高效的多线程编程方式,能够显著提高CPU的利用率。本文介绍了如何使用C++来实现一个手写的线程池。线程池的实现涉及到了线程的同步和互斥,需要使用 mutex 和 condition_variable等同步手段来保证安全性。借助线程池,我们可以更好地利用 CPU 资源,提高程序的性能和效率。

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复