C++高性能分布式服务器框架
从零开始重写sylar C++高性能分布式服务器框架
/**
* @filename scheduler.h
* @brief 协程调度模块
* @author L-ge
* @version 0.1
* @modify 2022-06-29
*/
#ifndef __SYLAR_SCHEDULER_H__
#define __SYLAR_SCHEDULER_H__
#include
#include
#include
#include
#include "fiber.h"
#include "thread.h"
namespace sylar
{
/**
* @brief 协程调度器
*/
class Scheduler
{
public:
typedef std::shared_ptr ptr;
typedef Mutex MutexType;
/**
* @brief 构造函数
*
* @param threads 线程数量
* @param use_caller 是否使用当前调用线程
* @param name 协程调度器名称
*/
Scheduler(size_t threads = 1, bool use_caller = true, const std::string& name = "");
virtual ~Scheduler();
const std::string& getName() const { return m_name; }
static Scheduler* GetThis();
/**
* @brief 返回当前协程调度器的调度协程(不一定是主协程)
*/
static Fiber* GetMainFiber();
void start();
void stop();
template
void schedule(FiberOrCb fc, int thread = -1)
{
bool need_tickle = false;
{
MutexType::Lock lk(m_mutex);
need_tickle = scheduleNoLock(fc, thread);
}
if(need_tickle)
{
tickle();
}
}
template
void schedule(InputIterator begin, InputIterator end)
{
bool need_tickle = false;
{
MutexType::Lock lk(m_mutex);
while(begin != end)
{
need_tickle = scheduleNoLock(&*begin, -1) || need_tickle;
++begin;
}
}
if(need_tickle)
{
tickle();
}
}
void switchTo(int thread = -1);
std::ostream& dump(std::ostream& os);
protected:
/**
* @brief 通知协程调度器有任务了
*/
virtual void tickle();
void run();
virtual bool stopping();
virtual void idle();
void setThis();
bool hasIdleThreads() { return m_idleThreadCount > 0; }
private:
template
bool scheduleNoLock(FiberOrCb fc, int thread)
{
bool need_tickle = m_fibers.empty();
FiberAndThread ft(fc, thread);
if(ft.fiber || ft.cb)
{
m_fibers.push_back(ft);
}
return need_tickle;
}
private:
struct FiberAndThread
{
Fiber::ptr fiber;
std::function cb;
int thread;
FiberAndThread(Fiber::ptr f, int thr)
: fiber(f)
, thread(thr)
{}
FiberAndThread(Fiber::ptr* f, int thr)
: thread(thr)
{
fiber.swap(*f);
}
FiberAndThread(std::function f, int thr)
: cb(f)
, thread(thr)
{}
FiberAndThread(std::function* f, int thr)
: thread(thr)
{
cb.swap(*f);
}
FiberAndThread()
: thread(-1)
{}
void reset()
{
fiber = nullptr;
cb = nullptr;
thread = -1;
}
};
private:
MutexType m_mutex;
/// 线程池
std::vector m_threads;
/// 任务队列
std::list m_fibers;
/// use_caller为true时有效,调度器所在线程的调用协程(但它是子协程)
Fiber::ptr m_rootFiber;
/// 协程调度器名称
std::string m_name;
protected:
/// 协程下的线程ID数组
std::vector m_threadIds;
size_t m_threadCount = 0;
/// 工作线程的数量
std::atomic m_activeThreadCount = {0};
/// 空闲线程的数量
std::atomic m_idleThreadCount = {0};
bool m_stopping = true;
bool m_autoStop = false;
/// use_caller为true时,调度器所在线程的线程id
int m_rootThread = 0;
};
class SchedulerSwitcher : public Noncopyable
{
public:
SchedulerSwitcher(Scheduler* target = nullptr);
~SchedulerSwitcher();
private:
Scheduler* m_caller;
};
}
#endif
#include "scheduler.h"
#include "fiber.h"
#include "macro.h"
#include "hook.h"
namespace sylar
{
static sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("system");
/// 当前线程的调度器,同一个调度器下的所有线程指向同一个调度器实例
static thread_local Scheduler* t_scheduler = nullptr;
/// 当前线程的调度协程,每个线程都独有一份,包括caller线程(caller线程的是当前线程的子协程)
static thread_local Fiber* t_scheduler_fiber = nullptr;
Scheduler::Scheduler(size_t threads, bool use_caller, const std::string& name)
: m_name(name)
{
SYLAR_ASSERT(threads > 0);
if(use_caller)
{
sylar::Fiber::GetThis(); // 这里面其实创建了当前线程的主协程
--threads;
SYLAR_ASSERT(GetThis() == nullptr);
t_scheduler = this;
// 创建调度协程(该线程的子协程)
m_rootFiber.reset(new Fiber(std::bind(&Scheduler::run, this), 0, true));
sylar::Thread::SetName(m_name);
t_scheduler_fiber = m_rootFiber.get();
m_rootThread = sylar::GetThreadId();
m_threadIds.push_back(m_rootThread);
}
else
{
m_rootThread = -1;
}
m_threadCount = threads;
}
Scheduler::~Scheduler()
{
SYLAR_ASSERT(m_stopping);
if(GetThis() == this)
{
t_scheduler = nullptr;
}
}
Scheduler* Scheduler::GetThis()
{
return t_scheduler;
}
Fiber* Scheduler::GetMainFiber()
{
return t_scheduler_fiber;
}
void Scheduler::start()
{
MutexType::Lock lk(m_mutex);
if(!m_stopping)
{
return;
}
m_stopping = false;
SYLAR_ASSERT(m_threads.empty());
// 初始化线程池
m_threads.resize(m_threadCount);
for(size_t i=0; igetId());
}
}
void Scheduler::stop()
{
m_autoStop = true;
if(m_rootFiber
&& m_threadCount == 0
&& (m_rootFiber->getState() == Fiber::TERM
|| m_rootFiber->getState() == Fiber::INIT))
{
SYLAR_LOG_INFO(g_logger) << this << " stopped";
m_stopping = true;
if(stopping())
{
return;
}
}
// 如果user_caller,则调用stop的线程也应该是它
if(m_rootThread != -1)
{
SYLAR_ASSERT(GetThis() == this);
}
else
{
SYLAR_ASSERT(GetThis() != this);
}
m_stopping = true;
for(size_t i=0; icall();
}
}
std::vector thrs;
{
MutexType::Lock lk(m_mutex);
thrs.swap(m_threads);
}
for(auto& i : thrs)
{
i->join();
}
}
/**
* @brief 切换线程(也可切换调度器)
*
* @param thread 线程id
*/
void Scheduler::switchTo(int thread)
{
SYLAR_ASSERT(Scheduler::GetThis() != nullptr);
if(Scheduler::GetThis() == this)
{
// 如果已经是当前调度器,而线程id未指定或已经是当前线程,则直接return掉
if(thread == -1 || thread == sylar::GetThreadId())
{
return;
}
}
// 再次加入任务队列里面,并让出当前协程的执行权
schedule(Fiber::GetThis(), thread);
Fiber::YieldToHold();
}
std::ostream& Scheduler::dump(std::ostream& os)
{
os << "[Scheduler name=" << m_name
<< " size=" << m_threadCount
<< " active_count=" << m_activeThreadCount
<< " idle_count=" << m_idleThreadCount
<< " stopping=" << m_stopping
<< " ]" << std::endl << " ";
for(size_t i=0; ithread != -1 && it->thread != sylar::GetThreadId())
{
++it;
tickle_me = true;
continue;
}
SYLAR_ASSERT(it->fiber || it->cb);
if(it->fiber && it->fiber->getState() == Fiber::EXEC)
{
++it;
continue;
}
ft = *it;
m_fibers.erase(it++);
++m_activeThreadCount;
is_active = true;
break;
}
// 当前线程拿完一个任务后,发现任务队列还有剩余,那么标记一下需要通知其他线程进行调度
tickle_me |= it!=m_fibers.end();
}
if(tickle_me)
{
tickle();
}
if(ft.fiber && (ft.fiber->getState() != Fiber::TERM
&& ft.fiber->getState() != Fiber::EXCEPT))
{
ft.fiber->swapIn(); // 切进去执行该协程
--m_activeThreadCount; // 等该协程出来的时候,活跃线程数便可以减1
// 该协程出来后,如果还是READY状态,则再把它进入到任务队列中
if(ft.fiber->getState() == Fiber::READY)
{
schedule(ft.fiber);
}
else if(ft.fiber->getState() != Fiber::TERM
&& ft.fiber->getState() != Fiber::EXCEPT)
{
ft.fiber->setState(Fiber::HOLD);
}
ft.reset();
}
else if(ft.cb) // 任务包装的是函数对象
{
if(cb_fiber)
{
cb_fiber->reset(ft.cb);
}
else
{
cb_fiber.reset(new Fiber(ft.cb));
}
ft.reset();
cb_fiber->swapIn();
--m_activeThreadCount;
if(cb_fiber->getState() == Fiber::READY)
{
schedule(cb_fiber);
cb_fiber.reset();
}
else if(cb_fiber->getState() == Fiber::EXCEPT
|| cb_fiber->getState() == Fiber::TERM)
{
cb_fiber->reset(nullptr);
}
else
{
cb_fiber->setState(Fiber::HOLD);
cb_fiber.reset();
}
}
else
{
if(is_active)
{
--m_activeThreadCount;
continue;
}
if(idle_fiber->getState() == Fiber::TERM)
{
SYLAR_LOG_INFO(g_logger) << "idle fiber term";
break;
}
++m_idleThreadCount;
idle_fiber->swapIn(); // 执行idle协程,其实是在忙等
--m_idleThreadCount;
if(idle_fiber->getState() != Fiber::TERM
&& idle_fiber->getState() != Fiber::EXCEPT)
{
idle_fiber->setState(Fiber::HOLD);
}
}
}
}
bool Scheduler::stopping()
{
MutexType::Lock lk(m_mutex);
return m_autoStop && m_stopping
&& m_fibers.empty() && m_activeThreadCount == 0;
}
void Scheduler::idle()
{
SYLAR_LOG_INFO(g_logger) << "idle";
while(!stopping())
{
sylar::Fiber::YieldToHold();
}
}
void Scheduler::setThis()
{
t_scheduler = this;
}
SchedulerSwitcher::SchedulerSwitcher(Scheduler* target)
{
m_caller = Scheduler::GetThis();
if(target)
{
target->switchTo();
}
}
SchedulerSwitcher::~SchedulerSwitcher()
{
if(m_caller)
{
m_caller->switchTo();
}
}
}
基于redis的参数查询服务