2.Google RPC-线程池

来源:互联网 发布:sql字段别名 编辑:程序博客网 时间:2024/06/05 11:28

Google RPC的线程池实现主要通过c++11标准来实现线程池模型,下面我们将来看看google rpc中对线程池的实现。

首先是定义个一个线程池接口,从代码中,找到了线程池的接口定义,接口的定义如下:

#ifndef GRPCXX_THREAD_POOL_INTERFACE_H#define GRPCXX_THREAD_POOL_INTERFACE_H#include <functional>namespace grpc {// A thread pool interface for running callbacks.class ThreadPoolInterface { public:  virtual ~ThreadPoolInterface() {}  // Schedule the given callback for execution.  virtual void ScheduleCallback(const std::function<void()>& callback) = 0;};}  // namespace grpc#endif  // GRPCXX_THREAD_POOL_INTERFACE_H

从这份代码声明中,我们可以看到,定义了一个ThreadPoolInterface的虚类,类中定义了一个纯虚函数,ScheduleCallback函数,负责回调函数的调用。接下来,我们将看看这个虚函数的子类,怎么样来实现接口的定义的。对于ThreadPoolInterface的继承,这个类的名字叫做ThreadPool类。这个类的定义在server文件夹下。现在我们来看看这个类的定义吧,ThreadPool类的定义如下:

#ifndef GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H#define GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H#include <grpc++/config.h>#include <grpc++/thread_pool_interface.h>#include <condition_variable>#include <thread>#include <mutex>#include <queue>#include <vector>namespace grpc {class ThreadPool GRPC_FINAL : public ThreadPoolInterface { public:  explicit ThreadPool(int num_threads);  ~ThreadPool();  void ScheduleCallback(const std::function<void()>& callback) GRPC_OVERRIDE; private:  std::mutex mu_;  std::condition_variable cv_;  bool shutdown_;  std::queue<std::function<void()>> callbacks_;  std::vector<std::thread> threads_;  void ThreadFunc();};}  // namespace grpc#endif  // GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
从上面代码看,我们可以知道,thread,mutex这些都是c++11中新增加的多线程支持,例外对于GRPC_FINAL是对final关键字的别名,这个也是c++11中的新特性,这个特性弱跟随在类定义的后面,说明这个类是不能被其他类继承的,若这个关键字用于函数后面,意味着这个函数是不能被继承的。

了解完这些后,我们来看看这个类的定义吧。

首先是explicit构造函数的使用,这个告诉我们要显式的调用构造函数。同时继承了threadpoolinterface的schedulecallback函数。在类的私有成员中定义了一个mutex变量来实现线程同步。还有一个条件变量用来判断队列是否为空,若空,则等待通知。shutdown_是一个线程退出的标志。queue和vector则是一个回调函数缓冲和线程池。ThreadFunc是一个线程函数,解释完这些变量后,让我们来看看线程池的具体实现。

#include "src/cpp/server/thread_pool.h"namespace grpc {void ThreadPool::ThreadFunc() {  for (;;) {    // Wait until work is available or we are shutting down.    std::unique_lock<std::mutex> lock(mu_);    if (!shutdown_ && callbacks_.empty()) {      cv_.wait(lock);    }    // Drain callbacks before considering shutdown to ensure all work    // gets completed.    if (!callbacks_.empty()) {      auto cb = callbacks_.front();      callbacks_.pop();      lock.unlock();      cb();    } else if (shutdown_) {      return;    }  }}ThreadPool::ThreadPool(int num_threads) : shutdown_(false) {  for (int i = 0; i < num_threads; i++) {    threads_.push_back(std::thread(&ThreadPool::ThreadFunc, this));  }}ThreadPool::~ThreadPool() {  {    std::lock_guard<std::mutex> lock(mu_);    shutdown_ = true;    cv_.notify_all();  }  for (auto t = threads_.begin(); t != threads_.end(); t++) {    t->join();  }}void ThreadPool::ScheduleCallback(const std::function<void()>& callback) {  std::lock_guard<std::mutex> lock(mu_);  callbacks_.push(callback);  cv_.notify_one();}}  // namespace grpc

从上到下一个一个分析,首先是线程函数,从线程函数中我们可以知道std::unique_ptr是一个智能指针,可以自动释放资源。从中我们可以知道,线程函数不断的判断回调函数池子里面是否有函数要执行,有则执行,没有使用条件变量阻塞。而构造函数负责初始化线程池。析构函数负责释放所有线程池改变线程退出状态,等待所有线程结束。

ScheduleCallback负责忘回调函数池子中添加函数,并且通知一个线程池子中有东西了。

这就是整个线程池的实现。

0 0
原创粉丝点击