thrift源码解析之concurrency


前言

由于thrift的server支持高并发,所以简单的将concurrency目录下的代码分析一下

thrift文章整理:
1.thrift简介
2.thrift源码解析之compiler
3.thrift源码解析之processor
4.thrift源码解析之protocol
5.thrift源码解析之transport
6.thrift源码解析之server
7.thrift源码解析之concurrency


Thread

先看一下c++的std::thread,大致如下
c++ thread看文章:https://blog.csdn.net/weixin_44705391/article/details/117674971

class thread{
        public:
                class id; 
                //构造函数
                thread() noexcept;
                thread( thread&& other ) noexcept;
                template< class Function, class... Args >
                explicit thread( Function&& f, Args&&... args );
                thread( const thread& ) = delete;
                    
                ~thread();
                //移动赋值:
                thread& operator=( thread&& other ) noexcept;
                //成员函数
                bool joinable() const noexcept;
                std::thread::id get_id() const noexcept;
                native_handle_type native_handle();
                static unsigned int hardware_concurrency() noexcept;
                void join();
                void detach();
                void swap( std::thread& other ) noexcept;
};

thrift的Thread如下:

class Thread final : public std::enable_shared_from_this<Thread> {
public:
  //std::thread内部类重命名为id_t
  typedef std::thread::id id_t;
  //线程状态
  enum STATE { uninitialized, starting, started, stopping, stopped };
  //成员函数
  static void threadMain(std::shared_ptr<Thread> thread);
  static inline bool is_current(id_t t) { return t == std::this_thread::get_id(); }//这两个函数封装了一下c++中的函数,不赘述
  static inline id_t get_current() { return std::this_thread::get_id(); }
  //构造/析构
  Thread(bool detached, std::shared_ptr<Runnable> runnable)
    : state_(uninitialized), detached_(detached) {
    this->_runnable = runnable;
  }
  ~Thread() {
    if (!detached_ && thread_->joinable()) {
        join();
    }
  }
  //成员函数
  STATE getState() const
  {
    Synchronized sync(monitor_);
    return state_;
  }
  void setState(STATE newState)
  {
    Synchronized sync(monitor_);
    state_ = newState;
    if (newState == started) {
	  monitor_.notify();
    }
  }
  void start() {
    if (getState() != uninitialized) {
      return;
    }
    std::shared_ptr<Thread> selfRef = shared_from_this();
    setState(starting);
    Synchronized sync(monitor_);
    thread_ = std::unique_ptr<std::thread>(new std::thread(threadMain, selfRef));
    if (detached_)
      thread_->detach();
    monitor_.wait();
  }
  void join() {
    if (!detached_ && state_ != uninitialized) {
      thread_->join();
    }
  }
  Thread::id_t getId() const { return thread_.get() ? thread_->get_id() : std::thread::id(); }
  std::shared_ptr<Runnable> runnable() const { return _runnable; }

private:
  std::shared_ptr<Runnable> _runnable;
  std::unique_ptr<std::thread> thread_;
  Monitor monitor_;
  STATE state_;
  bool detached_;
};

先看其中几个成员方法:

1.getState()

 STATE getState() const
  {
    Synchronized sync(monitor_);
    return state_;
  }

1.上锁
2.返回thread状态

2.setState()

  void setState(STATE newState)
  {
    Synchronized sync(monitor_);
    state_ = newState;
    if (newState == started) {
	  monitor_.notify();
    }
  }

1.上锁
2.修改thread状态
3.如果状态为started,那么条件变量激活

上述两个函数都执行了上锁,其原理和c++的lock_guard类似:
执行Synchronized 构造函数

class Synchronized {
public:
  Synchronized(const Monitor* monitor) : g(monitor->mutex()) {}
  Synchronized(const Monitor& monitor) : g(monitor.mutex()) {}

private:
  Guard g;
};

Guard 类:

class Guard : boost::noncopyable {
public:
  Guard(const Mutex& value, int64_t timeout = 0) : mutex_(&value) {
    if (timeout == 0) {
      value.lock();
    } else if (timeout < 0) {
      if (!value.trylock()) {
        mutex_ = nullptr;
      }
    } else {
      if (!value.timedlock(timeout)) {
        mutex_ = nullptr;
      }
    }
  }
  ~Guard() {
    if (mutex_) {
      mutex_->unlock();
    }
  }

  operator bool() const { return (mutex_ != nullptr); }

private:
  const Mutex* mutex_;
};

Monitor 类:集成了互斥锁和条件变量,让线程管理都能通过此类进行

class Monitor : boost::noncopyable {
public:
  Monitor();
  explicit Monitor(Mutex* mutex);
  explicit Monitor(Monitor* monitor);
  virtual ~Monitor();
  Mutex& mutex() const;
  virtual void lock() const;
  virtual void unlock() const;
  int waitForTimeRelative(const std::chrono::milliseconds &timeout) const;
  int waitForTimeRelative(uint64_t timeout_ms) const { return waitForTimeRelative(std::chrono::milliseconds(timeout_ms)); }
  int waitForTime(const std::chrono::time_point<std::chrono::steady_clock>& abstime) const;
  int waitForever() const;
  void wait(const std::chrono::milliseconds &timeout) const;
  void wait(uint64_t timeout_ms = 0ULL) const { this->wait(std::chrono::milliseconds(timeout_ms)); }
  virtual void notify() const;
  virtual void notifyAll() const;
private:
  class Impl;
  Impl* impl_;
};

其实现类impl_基本是封装了Mutex类
而thrift的Mutex是std::timed_mutex的封装,其实现类继承自std::timed_mutex。

monitor将mutex和condition_variable封装在一起(条件变量必须要配合互斥锁使用在 linux线程中讲过 ):

  const std::unique_ptr<Mutex> ownedMutex_;
  std::condition_variable_any conditionVariable_;
  Mutex* mutex_;

将条件变量的wait封装:

void wait(const std::chrono::milliseconds &timeout) {
    int result = waitForTimeRelative(timeout);
    if (result == THRIFT_ETIMEDOUT) {
      throw TimedOutException();
    } else if (result != 0) {
      throw TException("Monitor::wait() failed");
    }
  }

int waitForTimeRelative(const std::chrono::milliseconds &timeout) {
    if (timeout.count() == 0) {
      return waitForever();
    }
    assert(mutex_);
    auto* mutexImpl = static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
    assert(mutexImpl);
    std::unique_lock<std::timed_mutex> lock(*mutexImpl, std::adopt_lock);
    bool timedout = (conditionVariable_.wait_for(lock, timeout)
                     == std::cv_status::timeout);
    lock.release();
    return (timedout ? THRIFT_ETIMEDOUT : 0);
  }

int waitForTime(const std::chrono::time_point<std::chrono::steady_clock>& abstime) {
    assert(mutex_);
    auto* mutexImpl = static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
    assert(mutexImpl);
    std::unique_lock<std::timed_mutex> lock(*mutexImpl, std::adopt_lock);
    bool timedout = (conditionVariable_.wait_until(lock, abstime)
                     == std::cv_status::timeout);
    lock.release();
    return (timedout ? THRIFT_ETIMEDOUT : 0);
  }

int waitForever() {
    assert(mutex_);
    auto* mutexImpl = static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
    assert(mutexImpl);
    std::unique_lock<std::timed_mutex> lock(*mutexImpl, std::adopt_lock);	//假设调用方线程已拥有互斥的所有权
    conditionVariable_.wait(lock);
    lock.release();
    return 0;
  }

其实和条件变量的wait功能一模一样,但是因为封装导致线程不安全,所以又加锁使其变成线程安全的。

将条件变量的notify封装:(感觉这里也应该加上锁)

void notify() { conditionVariable_.notify_one(); }
void notifyAll() { conditionVariable_.notify_all(); }

3.threadMain()

void Thread::threadMain(std::shared_ptr<Thread> thread) {
  thread->setState(started);
  thread->runnable()->run();

  if (thread->getState() != stopping && thread->getState() != stopped) {
    thread->setState(stopping);
  }
}

4.start()

void start() {
    if (getState() != uninitialized) {
      return;
    }

    std::shared_ptr<Thread> selfRef = shared_from_this();
    setState(starting);

    Synchronized sync(monitor_);
    thread_ = std::unique_ptr<std::thread>(new std::thread(threadMain, selfRef));

    if (detached_)
      thread_->detach();
    monitor_.wait();
  }

大致执行过程:
1.设置状态为starting
2.创建threadMain线程,threadMain代码如上,是最小运行代码块
3.thread_->detach();让threadMain脱离主线程

其他成员变量不分析了,大同小异。

Runnable

class Runnable {

public:
  virtual ~Runnable() = default;
  virtual void run() = 0;

  virtual std::shared_ptr<Thread> thread() { return thread_.lock(); }
  virtual void thread(std::shared_ptr<Thread> value) { thread_ = value; }

private:
  std::weak_ptr<Thread> thread_;
};

Runnable被继承,FunctionRunner,ThreadManager,TimerManager,TEventloopServer,TNonblockingServer,TNonblockingIOThread,实现其中的run。

FunctionRunner

提供把函数包装成Runnable的功能。不细看

TimerManager

class TimerManager {

public:
  class Task;
  typedef std::weak_ptr<Task> Timer;

  TimerManager();

  virtual ~TimerManager();

  virtual std::shared_ptr<const ThreadFactory> threadFactory() const;

  virtual void threadFactory(std::shared_ptr<const ThreadFactory> value);

  virtual void start();

  virtual void stop();

  virtual size_t taskCount() const;

  virtual Timer add(std::shared_ptr<Runnable> task, const std::chrono::milliseconds &timeout);
  Timer add(std::shared_ptr<Runnable> task, uint64_t timeout) { return add(task,std::chrono::milliseconds(timeout)); }

  virtual Timer add(std::shared_ptr<Runnable> task, const std::chrono::time_point<std::chrono::steady_clock>& abstime);
  virtual void remove(std::shared_ptr<Runnable> task);

  virtual void remove(Timer timer);

  enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };

  virtual STATE state() const;

private:
  std::shared_ptr<const ThreadFactory> threadFactory_;
  friend class Task;
  std::multimap<std::chrono::time_point<std::chrono::steady_clock>, std::shared_ptr<Task> > taskMap_;
  size_t taskCount_;
  Monitor monitor_;
  STATE state_;
  class Dispatcher;
  friend class Dispatcher;
  std::shared_ptr<Dispatcher> dispatcher_;
  std::shared_ptr<Thread> dispatcherThread_;
  using task_iterator = decltype(taskMap_)::iterator;
  typedef std::pair<task_iterator, task_iterator> task_range;
};
class TimerManager::Task : public Runnable {

public:
  enum STATE { WAITING, EXECUTING, CANCELLED, COMPLETE };

  Task(shared_ptr<Runnable> runnable) : runnable_(runnable), state_(WAITING) {}

  ~Task() override = default;

  void run() override {
    if (state_ == EXECUTING) {
      runnable_->run();
      state_ = COMPLETE;
    }
  }

  bool operator==(const shared_ptr<Runnable> & runnable) const { return runnable_ == runnable; }

  task_iterator it_;

private:
  shared_ptr<Runnable> runnable_;
  friend class TimerManager::Dispatcher;
  STATE state_;
};
class TimerManager::Dispatcher : public Runnable {

public:
  Dispatcher(TimerManager* manager) : manager_(manager) {}

  ~Dispatcher() override = default;

  void run() override {
    {
      Synchronized s(manager_->monitor_);
      if (manager_->state_ == TimerManager::STARTING) {
        manager_->state_ = TimerManager::STARTED;
        manager_->monitor_.notifyAll();
      }
    }

    do {
      std::set<shared_ptr<TimerManager::Task> > expiredTasks;
      {
        Synchronized s(manager_->monitor_);
        task_iterator expiredTaskEnd;
        auto now = std::chrono::steady_clock::now();
        while (manager_->state_ == TimerManager::STARTED
               && (expiredTaskEnd = manager_->taskMap_.upper_bound(now))
                  == manager_->taskMap_.begin()) {
          std::chrono::milliseconds timeout(0);
          if (!manager_->taskMap_.empty()) {
            timeout = std::chrono::duration_cast<std::chrono::milliseconds>(manager_->taskMap_.begin()->first - now);
            //because the unit of steady_clock is smaller than millisecond,timeout may be 0.
            if (timeout.count() == 0) {
              timeout = std::chrono::milliseconds(1);
            }
            manager_->monitor_.waitForTimeRelative(timeout);
          } else {
            manager_->monitor_.waitForTimeRelative(0);
          }
          now = std::chrono::steady_clock::now();
        }

        if (manager_->state_ == TimerManager::STARTED) {
          for (auto ix = manager_->taskMap_.begin(); ix != expiredTaskEnd; ix++) {
            shared_ptr<TimerManager::Task> task = ix->second;
            expiredTasks.insert(task);
            task->it_ = manager_->taskMap_.end();
            if (task->state_ == TimerManager::Task::WAITING) {
              task->state_ = TimerManager::Task::EXECUTING;
            }
            manager_->taskCount_--;
          }
          manager_->taskMap_.erase(manager_->taskMap_.begin(), expiredTaskEnd);
        }
      }

      for (const auto & expiredTask : expiredTasks) {
        expiredTask->run();
      }

    } while (manager_->state_ == TimerManager::STARTED);

    {
      Synchronized s(manager_->monitor_);
      if (manager_->state_ == TimerManager::STOPPING) {
        manager_->state_ = TimerManager::STOPPED;
        manager_->monitor_.notifyAll();
      }
    }
    return;
  }

private:
  TimerManager* manager_;
  friend class TimerManager;
};

ThreadManager

线程池管理类

这个类管理一个线程池。 它使用 ThreadFactory 来创建线程。
它实际上从未创建或销毁工作线程,而是维护有关空闲线程数、活动线程数、任务积压以及平均等待和服务时间的统计信息,并将有趣的转换通知绑定到此管理器实例的PoolPolicy 对象。 然后由 PoolPolicy 对象决定是否需要调整线程池大小并调用该对象的 addWorker 和 removeWorker 方法进行更改。
这种设计允许不同的策略实现使用此代码来处理基本的工作线程管理和工作任务执行并专注于策略问题。最简单的策略 StaticPolicy 除了创建固定数量的线程之外什么都不做。

class ThreadManager {
protected:
  ThreadManager() = default;
public:
  typedef std::function<void(std::shared_ptr<Runnable>)> ExpireCallback;
  virtual ~ThreadManager() = default;
  virtual void start() = 0;
  virtual void stop() = 0;

  enum STATE { UNINITIALIZED, STARTING, STARTED, JOINING, STOPPING, STOPPED };
  virtual STATE state() const = 0;
  virtual std::shared_ptr<ThreadFactory> threadFactory() const = 0;
  virtual void threadFactory(std::shared_ptr<ThreadFactory> value) = 0;
  virtual void addWorker(size_t value = 1) = 0;
  virtual void removeWorker(size_t value = 1) = 0;
  virtual size_t idleWorkerCount() const = 0;
  virtual size_t workerCount() const = 0;
  virtual size_t pendingTaskCount() const = 0;
  virtual size_t totalTaskCount() const = 0;
  virtual size_t pendingTaskCountMax() const = 0;
  virtual size_t expiredTaskCount() const = 0;
  virtual void add(std::shared_ptr<Runnable> task,
                   int64_t timeout = 0LL,
                   int64_t expiration = 0LL) = 0;
  virtual void remove(std::shared_ptr<Runnable> task) = 0;
  virtual std::shared_ptr<Runnable> removeNextPending() = 0;
  virtual void removeExpiredTasks() = 0;
  virtual void setExpireCallback(ExpireCallback expireCallback) = 0;

  static std::shared_ptr<ThreadManager> newThreadManager();
  static std::shared_ptr<ThreadManager> newSimpleThreadManager(size_t count = 4, size_t pendingTaskCountMax = 0);

  class Task;
  class Worker;
  class Impl;
};

1.Task

class ThreadManager::Task : public Runnable {

public:
  enum STATE { WAITING, EXECUTING, TIMEDOUT, COMPLETE };

  Task(shared_ptr<Runnable> runnable, uint64_t expiration = 0ULL)
    : runnable_(runnable),
      state_(WAITING) {
        if (expiration != 0ULL) {
          expireTime_.reset(new std::chrono::steady_clock::time_point(std::chrono::steady_clock::now() + std::chrono::milliseconds(expiration)));
        }
    }

  ~Task() override = default;

  void run() override {
    if (state_ == EXECUTING) {
      runnable_->run();
      state_ = COMPLETE;
    }
  }

  shared_ptr<Runnable> getRunnable() { return runnable_; }

  const unique_ptr<std::chrono::steady_clock::time_point> & getExpireTime() const { return expireTime_; }

private:
  shared_ptr<Runnable> runnable_;
  friend class ThreadManager::Worker;
  STATE state_;
  unique_ptr<std::chrono::steady_clock::time_point> expireTime_;
};

2.Worker

class ThreadManager::Worker : public Runnable {
  enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };

public:
  Worker(ThreadManager::Impl* manager) : manager_(manager), state_(UNINITIALIZED) {}

  ~Worker() override = default;

private:
  bool isActive() const {
    return (manager_->workerCount_ <= manager_->workerMaxCount_)
           || (manager_->state_ == JOINING && !manager_->tasks_.empty());
  }

public:
  /**
   * Worker entry point
   *
   * As long as worker thread is running, pull tasks off the task queue and
   * execute.
   */
  void run() override {
    Guard g(manager_->mutex_);

    /**
     * This method has three parts; one is to check for and account for
     * admitting a task which happens under a lock.  Then the lock is released
     * and the task itself is executed.  Finally we do some accounting
     * under lock again when the task completes.
     */

    /**
     * Admitting
     */

    /**
     * Increment worker semaphore and notify manager if worker count reached
     * desired max
     */
    bool active = manager_->workerCount_ < manager_->workerMaxCount_;
    if (active) {
      if (++manager_->workerCount_ == manager_->workerMaxCount_) {
        manager_->workerMonitor_.notify();
      }
    }

    while (active) {
      /**
        * While holding manager monitor block for non-empty task queue (Also
        * check that the thread hasn't been requested to stop). Once the queue
        * is non-empty, dequeue a task, release monitor, and execute. If the
        * worker max count has been decremented such that we exceed it, mark
        * ourself inactive, decrement the worker count and notify the manager
        * (technically we're notifying the next blocked thread but eventually
        * the manager will see it.
        */
      active = isActive();

      while (active && manager_->tasks_.empty()) {
        manager_->idleCount_++;
        manager_->monitor_.wait();
        active = isActive();
        manager_->idleCount_--;
      }

      shared_ptr<ThreadManager::Task> task;

      if (active) {
        if (!manager_->tasks_.empty()) {
          task = manager_->tasks_.front();
          manager_->tasks_.pop_front();
          if (task->state_ == ThreadManager::Task::WAITING) {
            // If the state is changed to anything other than EXECUTING or TIMEDOUT here
            // then the execution loop needs to be changed below.
            task->state_ =
                (task->getExpireTime() && *(task->getExpireTime()) < std::chrono::steady_clock::now()) ?
                    ThreadManager::Task::TIMEDOUT :
                    ThreadManager::Task::EXECUTING;
          }
        }

        /* If we have a pending task max and we just dropped below it, wakeup any
            thread that might be blocked on add. */
        if (manager_->pendingTaskCountMax_ != 0
            && manager_->tasks_.size() <= manager_->pendingTaskCountMax_ - 1) {
          manager_->maxMonitor_.notify();
        }
      }

      /**
       * Execution - not holding a lock
       */
      if (task) {
        if (task->state_ == ThreadManager::Task::EXECUTING) {

          // Release the lock so we can run the task without blocking the thread manager
          manager_->mutex_.unlock();

          try {
            task->run();
          } catch (const std::exception& e) {
            GlobalOutput.printf("[ERROR] task->run() raised an exception: %s", e.what());
          } catch (...) {
            GlobalOutput.printf("[ERROR] task->run() raised an unknown exception");
          }

          // Re-acquire the lock to proceed in the thread manager
          manager_->mutex_.lock();

        } else if (manager_->expireCallback_) {
          // The only other state the task could have been in is TIMEDOUT (see above)
          manager_->expireCallback_(task->getRunnable());
          manager_->expiredCount_++;
        }
      }
    }

    /**
     * Final accounting for the worker thread that is done working
     */
    manager_->deadWorkers_.insert(this->thread());
    if (--manager_->workerCount_ == manager_->workerMaxCount_) {
      manager_->workerMonitor_.notify();
    }
  }

private:
  ThreadManager::Impl* manager_;
  friend class ThreadManager::Impl;
  STATE state_;
};

3.impl

class ThreadManager::Impl : public ThreadManager {

public:
  Impl()
    : workerCount_(0),
      workerMaxCount_(0),
      idleCount_(0),
      pendingTaskCountMax_(0),
      expiredCount_(0),
      state_(ThreadManager::UNINITIALIZED),
      monitor_(&mutex_),
      maxMonitor_(&mutex_),
      workerMonitor_(&mutex_) {}

  ~Impl() override { stop(); }

  void start() override;
  void stop() override;

  ThreadManager::STATE state() const override { return state_; }

  shared_ptr<ThreadFactory> threadFactory() const override {
    Guard g(mutex_);
    return threadFactory_;
  }

  void threadFactory(shared_ptr<ThreadFactory> value) override {
    Guard g(mutex_);
    if (threadFactory_ && threadFactory_->isDetached() != value->isDetached()) {
      throw InvalidArgumentException();
    }
    threadFactory_ = value;
  }

  void addWorker(size_t value) override;

  void removeWorker(size_t value) override;

  size_t idleWorkerCount() const override { return idleCount_; }

  size_t workerCount() const override {
    Guard g(mutex_);
    return workerCount_;
  }

  size_t pendingTaskCount() const override {
    Guard g(mutex_);
    return tasks_.size();
  }

  size_t totalTaskCount() const override {
    Guard g(mutex_);
    return tasks_.size() + workerCount_ - idleCount_;
  }

  size_t pendingTaskCountMax() const override {
    Guard g(mutex_);
    return pendingTaskCountMax_;
  }

  size_t expiredTaskCount() const override {
    Guard g(mutex_);
    return expiredCount_;
  }

  void pendingTaskCountMax(const size_t value) {
    Guard g(mutex_);
    pendingTaskCountMax_ = value;
  }

  void add(shared_ptr<Runnable> value, int64_t timeout, int64_t expiration) override;

  void remove(shared_ptr<Runnable> task) override;

  shared_ptr<Runnable> removeNextPending() override;

  void removeExpiredTasks() override {
    removeExpired(false);
  }

  void setExpireCallback(ExpireCallback expireCallback) override;

private:
  /**
   * Remove one or more expired tasks.
   * \param[in]  justOne  if true, try to remove just one task and return
   */
  void removeExpired(bool justOne);

  /**
   * \returns whether it is acceptable to block, depending on the current thread id
   */
  bool canSleep() const;

  /**
   * Lowers the maximum worker count and blocks until enough worker threads complete
   * to get to the new maximum worker limit.  The caller is responsible for acquiring
   * a lock on the class mutex_.
   */
  void removeWorkersUnderLock(size_t value);

  size_t workerCount_;
  size_t workerMaxCount_;
  size_t idleCount_;
  size_t pendingTaskCountMax_;
  size_t expiredCount_;
  ExpireCallback expireCallback_;

  ThreadManager::STATE state_;
  shared_ptr<ThreadFactory> threadFactory_;

  friend class ThreadManager::Task;
  typedef std::deque<shared_ptr<Task> > TaskQueue;
  TaskQueue tasks_;
  Mutex mutex_;
  Monitor monitor_;
  Monitor maxMonitor_;
  Monitor workerMonitor_;       // used to synchronize changes in worker count

  friend class ThreadManager::Worker;
  std::set<shared_ptr<Thread> > workers_;
  std::set<shared_ptr<Thread> > deadWorkers_;
  std::map<const Thread::id_t, shared_ptr<Thread> > idMap_;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值