holyya.com
2025-09-04 06:27:22 Thursday
登录
文章检索 我的文章 写文章
如何使用C++中的std::future来实现线程池?
2023-07-07 06:08:29 深夜i     --     --
C++ std::future 线程池 实现
return this->stop || !this->tasks.empty();

在多线程编程中,线程池被广泛应用以提高程序的并发性和性能。而C++中的std::future则是一种很好的实现线程池的方式。本文将介绍如何使用C++中的std::future来实现线程池。

首先,我们需要创建一个线程池类,该类包含一个队列和一组线程和一个互斥量,确保线程安全。这个类应该包含公共接口,允许客户端线程提交任务到线程池。

在C++11标准中,std::async函数可以用来创建异步任务,返回一个std::future对象,我们可以通过该对象获取异步任务的执行结果。接着,我们可以将这些std::future对象存储在任务队列中,并在空闲线程中执行它们。当线程池中的线程变为空闲状态时,它们就可以处理该队列中正在等待执行的任务。

下面是一个简单的线程池类的实现,采用std::future来实现异步任务的执行:


#include <future>

#include <queue>

#include <vector>

#include <functional>

#include <thread>

#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]

        {

          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, class... Args>

  auto enqueue(F&& f, Args&&... args)

    -> std::future<typename std::result_of<F(Args...)>::type>

  {

    using return_type = typename std::result_of<F(Args...)>::type;

    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(queue_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(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;

};

在上面的代码中,我们创建了一个包含多个线程的线程池,并且在ThreadPool类中定义了一个enqueue函数来向任务队列中添加任务。该enqueue函数接受一个可调用对象和可调用对象的参数,并将它们作为一个任务压入任务队列中,返回一个std::future对象,可用于获取异步任务的返回值。线程池中的每个线程都会反复地从队列中获取任务并执行它们,直到线程池停止运行。

我们可以使用如下代码来使用ThreadPool类:


#include <iostream>

#include <chrono>

void foo(int n)

{

  std::this_thread::sleep_for(std::chrono::seconds(1));

  std::cout << "Result = " << n * 2 << std::endl;

}

int main()

{

  ThreadPool tp(4);

  std::cout << "Enqueuing tasks..." << std::endl;

  for (int i = 0; i < 8; ++i)

  {

    auto result = tp.enqueue(foo, i);

  }

  std::this_thread::sleep_for(std::chrono::seconds(5));

  std::cout << "Done!" << std::endl;

  return 0;

}

在上面的代码中,我们首先创建一个ThreadPool对象,它包含4个线程。接着,我们使用enqueue函数将8个任务添加到线程池中。每个任务在执行时都休眠1秒钟,并将其参数乘以2作为结果输出。我们在主线程中休眠5秒钟来确保所有的任务都执行完毕。最后,我们输出“Done!”以表示程序的结束。

总结来说,使用C++中的std::future来实现线程池是一种高效的多线程编程方式。通过使用std::future,我们可以轻松地获取异步任务的返回值,并避免手动管理线程和锁,从而减少了错误的可能性。使用上述代码实现的ThreadPool类是一个很好的参考实现,可以用于快速实现线程池。

  
  

评论区

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