[学习分享]----sylar服务器框架源码阅读--协程调度模块

协程调度模块

sylar作者在本站的地址为 这里,也可以查看 作者主页,也有视频教程可以 点击这里。此外,也可以看一下赵路强大佬的关于sylar协程模块的博客 点击这里,我本人在阅读sylar源码的时候也是参考了赵路强大佬的解析 可以点击这里。
各位看官也可以加我的qq和我讨论2511010742

在上期博客中,实现了两个协程之间的切换,但是单独的切换两个协程并不能做到什么高效率的事情,在一个子协程中不可以直接调用另一个子协程,必须先切换回主协程。在本节中,解决了这个问题,可以通过在子协程中向调度器添加另一个子协程,这样的话就变相的实现了在子协程中添加子协程的操作。

协程调度流程简介

当创建了很多协程之后,将这些协程按照一定规则消耗掉就称为协程调度,此外还实现了添加协程的功能。简而言之,协程调度器创建N个线程,利用这N个线程去运行M个协程,实现了一个N-M协程调度器,协程可以在线程中切换,也可以指定线程去运行协程。

对于协程调度器,不仅可以调度协程,也应该可以直接调度函数。sylar的协程调度器支持多线程,并且main函数所在的线程也可以参加到协程调度中来,支持添加协程或者函数作为调度的对象。协程调度器在初始化时会传入一个use_caller布尔值,由这个布尔变量决定是否将main函数所在的线程也添加到协程调度中去。如果使用的话,就可以少创建一个线程,减少了系统的开销。

在调度器Scheduler中,可以使用scheduler方法添加任务到调度器中,将这些任务保存到内部的一个任务队列中,之后调用start方法启动协程调度器,在start方法中会创建一个线程池,如果use_caller为true的话就创建N-1个线程,反之创建N个线程。每个线程都会创建一个调度协程,这个协程专门用来进行任务调度,当use_caller为true时,main函数所在的线程会自行创建调度协程。

每个线程的调度协程都会运行各自相应的run方法,在run方法中,主要负责从调度器的任务队列中取出任务并执行,这里取出的任务可以看作调度协程的子协程,他们俩的调度关系就是上一节中讲述的简单切换方式,由调度协程切换到任务协程,执行完之后再切换到调度协程,继续取任务执行,每个子任务协程都必须要切换回调度协程。如果任务队列为空,那么就会进入一个idle空闲协程中,目前这个空闲协程什么也不做,进入空闲协程之后就会退出,此时还是没有新任务,就又进入空闲协程,然后又退出,以此往复,直到有新任务到来才会取执行新的任务调度。

在main函数线程中,第一个创建的主协程并不是调度协程,主协程的子协程才是真正的调度协程,因为main线程中,天生就有一个主协程。而在其他线程中,调度协程就是线程的主协程(这是sylar协程调度模块中很难理解的地方)。非main线程中,主协程就是调度协程,任务调度则是主协程直接切换到任务子协程运行,再切换回主协程,以此往复。而在main线程中,程序一开始就运行在main线程的主协程中,所以main线程的主协程会先切换到调度协程,再由调度协程去调度任务子协程,等到没有任务时,并且要退出调度器时,调度协程才会切换回主协程,也就是回到main函数中继续运行直到程序结束。

sylar的协程调度模块通过scheduler方法添加新的任务,它还可以指定一个具体的线程去执行新添加的任务,在scheduler方法中,如果目前任务队列已经为空了,那么添加任务之后会调用一次tickle方法,这个方法会通知各个线程有新任务到来了。在执行任务的途中也可以调用scheduler来添加任务,通过GetThis()方法获取当前调度器,再通过调用调度器的scheduler方法来添加任务。

关于协程调度器的停止也要分为两种情况,即main函数线程有没有参与调度,如果没有的话,在调用stop方法之后,其他线程如果没有任务了,会先进入一次idle空闲协程,然后再退出,此时idle协程的状态就是已完成状态,这个线程就优雅的退出了。如果main函数线程参与了协程调度的话,再stop方法中会单独的执行一次main线程的调度协程,在没有任务之后就会退出到main函数线程的主协程,之后整个调度器就优雅的退出了。因为main函数线程的调度协程是在stop方法中去执行的,所以在只有main线程参与调度的情况下,这些需要调度的任务会在调度器停止时才会被调度。

当然,以上是sylar设计的协程调度器,我们在使用时也可以进行相应的优化,可以适当的改进。

下图为不使用main线程调度的简单流程,创建了一个额外的调度线程。
[学习分享]----sylar服务器框架源码阅读--协程调度模块_第1张图片
下图为使用main线程的流程图。使用main函数所在的线程,而且还额外创建了一个线程,这样就有两个线程参与调度。此图中的m_root_fiber就是main线程的调度协程。

[学习分享]----sylar服务器框架源码阅读--协程调度模块_第2张图片

源码阅读

我会尽可能地将sylar源码的注释写明白。首先是协程调度器Sheduler类的定义

namespace sylar {
/**
 * @brief 协程调度器
 * @details 封装的是N-M的协程调度器
 *          内部有一个线程池,支持协程在线程池里面切换
 */ 
class Scheduler {
public:
    typedef std::shared_ptr<Scheduler> ptr;
    typedef Mutex MutexType;

    /**
     * @brief 构造函数
     * @param[in] threads 线程数量
     * @param[in] use_caller 是否使用当前调用线程
     * @param[in] name 协程调度器名称
     */
    Scheduler(size_t threads = 1, bool use_caller = true, const std::string& name = "");

    virtual ~Scheduler();

    // get scheduler name
    const std::string& getName() const { return m_name;}

    // get curr scheduler p
    static Scheduler* GetThis();

    // 返回当前协程调度器的调度携程(不一定是主协程)
    static Fiber* GetMainFiber();

    // 启动协程调度器
    void start();

    // 停止协程调度器
    void stop();

    /**
     * @brief 调度协程
     * @param[in] fc 协程或函数
     * @param[in] thread 协程执行的线程id,-1标识任意线程
     */
    template<class FiberOrCb>
    void schedule(FiberOrCb fc, int thread = -1) {
        bool need_tickle = false;
        {
            MutexType::Lock lock(m_mutex);
            need_tickle = scheduleNoLock(fc, thread);
        }

        if(need_tickle) {
            std::cout << "[INFO]   add fc in here, tickle other thread" << std::endl;
            tickle();
            //std::cout << "[INFO]   tell over" << std::endl;
        }
    }

    /**
     * @brief 批量调度协程
     * @param[in] begin 协程数组的开始
     * @param[in] end 协程数组的结束
     */
    template<class InputIterator>
    void schedule(InputIterator begin, InputIterator end) {
        bool need_tickle = false;
        {
            MutexType::Lock lock(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:
    // 通知调度器有任务
    virtual void tickle();

    // 协程调度函数
    void run();

    // 返回是否可以停止
    virtual bool stopping();

    // 协程无任务时可调度执行idle协程
    virtual void idle();

    // 设置当前的协程调度器
    void setThis();

    // 是否有空闲协程    
    bool hasIdleThreads() { return m_idleThreadCount > 0;}

private:
    // 协程调度启动,添加任务
    template<class FiberOrCb>
    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;
    }

    /**
     * @brief 协程/函数/线程组
     */
    struct FiberAndThread {
        // 协程
        Fiber::ptr fiber;
        // 协程执行函数
        std::function<void()> cb;
        // 线程id
        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<void()> f, int thr)
            :cb(f), thread(thr) {}

        FiberAndThread(std::function<void()>* f, int thr)
            :thread(thr) {
            cb.swap(*f);
        }

        FiberAndThread()
            :thread(-1) {}

        // 重置数据
        void reset() {
            fiber = nullptr;
            cb = nullptr;
            thread = -1;
        }
    };

private:
    // Mutex
    MutexType m_mutex;
    // 线程池
    std::vector<Thread::ptr> m_threads;
    // 待执行的协程队列
    std::list<FiberAndThread> m_fibers;
    // use_caller为真时有效,调度协程
    Fiber::ptr m_rootFiber;
    // 协程调度器名称
    std::string m_name;
protected:
    // 协程下的线程id数组
    std::vector<int> m_threadIds;
    // 线程数量
    size_t m_threadCount = 0;
    // 工作线程数量
    std::atomic<size_t> m_activeThreadCount = {0};
    // 空闲线程数量
    std::atomic<size_t> m_idleThreadCount = {0};
    // 是否正在停止
    bool m_stopping = true;
    // 是否自动停止
    bool m_autoStop = false;
    // 主线程id
    int m_rootThread = 0;
};

接下来是方法实现

namespace sylar {

// 当前线程的调度器,同一个调度器控制下的所有线程的调度器都是相同的
static thread_local Scheduler* t_scheduler = nullptr;

// 当前线程的调度协程,每一个线程都有一个调度协程,也包括main函数线程
static thread_local Fiber* t_scheduler_fiber = nullptr;

/*
    t_scheduler_fiber保存当前线程的的调度协程
    Fiber::t_fiber保存当前正在运行的协程
    Fiber::t_thread_fiber保存的是当前线程的主协程
*/

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(); // 创建main函数线程第一个协程
        --threads;	// 使用main线程参与调度,就可以少创建一个额外的调度线程

        // SYLAR_ASSERT(GetThis() == nullptr);
        t_scheduler = this;

        // 重新创建主协程,将run方法与m_rootFiber绑定
        // 主协程在上面已经通过GetThis方法创建过了,所以这里说是重新创建
        // 其实就是main函数线程的调度协程,
        // 因为其他每个调度线程都是他们的主协程作为调度协程的
        // 所以才取了m_rootFiber来命名main线程的调度协程,其实他并不是这个线程的主协程。
        m_rootFiber.reset(new Fiber(std::bind(&Scheduler::run, this), 0, true));

        // 将main线程的m_rootFiber协程赋给main线程的调度协程
        // 因为t_scheduler_fiber保存每个线程的调度协程,所以也将m_rootFiber赋给它
        t_scheduler_fiber = m_rootFiber.get();
        // 将主线程放入线程池管理
        m_threadIds.push_back(m_rootThread);
    } else {
        m_rootThread = -1;
    }
    // 如果不使用main线程的话,那么需要创建的线程数不变
    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() {
    std::cout << "[INFO]   Scheduler start!" << std::endl;
    MutexType::Lock lock(m_mutex);
    if(!m_stopping) {
        return;
    }
    m_stopping = false;
    // SYLAR_ASSERT(m_threads.empty());

    // 设置线程池大小
    m_threads.resize(m_threadCount);
    for(size_t i = 0; i < m_threadCount; ++i) {
        // 重置每个线程的调度器执行函数
        // 将run方法绑定为这些线程的入口函数
        m_threads[i].reset(new Thread(std::bind(&Scheduler::run, this)
                            , m_name + "_" + std::to_string(i)));
        m_threadIds.push_back(m_threads[i]->getId());
        std::cout << "[INFO]   create thread No." << i << std::endl;
    }
    lock.unlock();
}

void Scheduler::stop() {
    std::cout << "[INFO]   in stop func" << std::endl;
    m_autoStop = true;
    if(m_rootFiber
            && m_threadCount == 0
            && (m_rootFiber->getState() == Fiber::TERM
                || m_rootFiber->getState() == Fiber::INIT)) {
        std::cout << "[DEBUG]  " << this << " stopped" << std::endl;
        m_stopping = true;

        if(stopping()) {    // 留给子类实现
            return;
        }
    }

    if(m_rootThread != -1) {
        // SYLAR_ASSERT(GetThis() == this);
    } else {
        // SYLAR_ASSERT(GetThis() != this);
    }

    m_stopping = true;
    for(size_t i = 0; i < m_threadCount; i++) {
        std::cout << "[INFO]   tickle other thread stop" << std::endl;
        tickle();
    }

    if(m_rootFiber) {
        std::cout << "[INFO]   m_rootFiber tickle" << std::endl;
        tickle();
    }

    if(m_rootFiber) {
        if(!stopping()) {
            std::cout << "[INFO]   m_rootFiber run" << std::endl;
            m_rootFiber->call();
            /*
				此处为main线程的调度协程启动入口,这里是调用的是call方法
				它执行完之后会返回到main线程的主协程上
				目前运行到这一行就是处于main的主协程。这里的主协程并不是调度协程
				##########################
				而其他线程调用的是swapin方法,它会返回到对应线程的主协程,也就是调度协程
			*/
        }
    }

    std::vector<Thread::ptr> thrs;
    {
        MutexType::Lock lock(m_mutex);
        thrs.swap(m_threads);
    }

    for(auto& i : thrs) {
        i->join();
    }
    std::cout << "[INFO]   stop func over" << std::endl;
}

// 设置当前调度器
void Scheduler::setThis() {
    t_scheduler = this;
}

void Scheduler::run() {
    std::cout << "[DEBUG]  " << m_name << " run" << std::endl;

    setThis();
    //std::cout << "[DEBUG]  " << std::endl;
    // 如果当前线程不是主线程的话
    if(syscall(SYS_gettid) != m_rootThread) {
        // 那么当前线程的调度协程就是执行run方法的协程
        t_scheduler_fiber = Fiber::GetThis().get();
    }

    // 创建idle空闲协程
    Fiber::ptr idle_fiber(new Fiber(std::bind(&Scheduler::idle, this)));
    std::cout << "[DEBUG]  create idle fiber" << std::endl;
    // 创建回调协程
    Fiber::ptr cb_fiber;

    // 创建一个协程/函数/线程组
    FiberAndThread ft;
    // 接下来会一直循环搜索需要调度的任务
    while(true) {
        // 将ft其中的协程、回调置空
        ft.reset();
        bool tickle_me = false; // 是否提醒其他线程进行任务调度
        bool is_active = false;
        {
            MutexType::Lock lock(m_mutex);
            auto it = m_fibers.begin();
            while(it != m_fibers.end()) {   // 从协程队列的开始到结束
                // 说明指定了线程去执行,但不是当前线程,标记一下通知其他线程去调度
                // 然后跳过,继续查看下一个任务
                if(it->thread != -1 && it->thread != syscall(SYS_gettid)) {
                    ++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) {
            std::cout << "[INFO]   tell other thread, the fc are here" << std::endl;
            tickle();
        }

        // ft这个任务的状态不等于结束也不等于异常
        if(ft.fiber && (ft.fiber->getState() != Fiber::TERM
                        && ft.fiber->getState() != Fiber::EXCEPT)) {
            ft.fiber->swapIn(); // 执行此协程
            --m_activeThreadCount;

            // 如果此协程状态又被设置为READY状态,就重新将其加入调度队列
            // 这说明ft任务半路推出了
            if(ft.fiber->getState() == Fiber::READY) {
                schedule(ft.fiber);
            } else if(ft.fiber->getState() != Fiber::TERM
                    && ft.fiber->getState() != Fiber::EXCEPT) {
                ft.fiber->m_state = Fiber::HOLD;
                // 如果ft状态不等于结束也不等于异常也不等于就绪的话
                // 就将其设置为暂停
            }
            ft.reset(); // 清除ft
        } else if(ft.cb) {  // 如果ft是一个callback回调函数的话
            if(cb_fiber) {  // 如果cb以初始化的话
                cb_fiber->reset(ft.cb); // 普通指针
            } else {        // 没初始化
                cb_fiber.reset(new Fiber(ft.cb)); // 智能指针
                std::cout << "[INFO]   it is cb_fiber.reset(new Fiber(ft.cb))" << std::endl;
            }
            ft.reset(); // 清除ft
            cb_fiber->swapIn(); // 去执行cb
            --m_activeThreadCount;
            // 执行到半路退出了
            if(cb_fiber->getState() == Fiber::READY) {
                schedule(cb_fiber); // 重新加载
                cb_fiber.reset();   // 清除cb
            } else if(cb_fiber->getState() == Fiber::EXCEPT
                    || cb_fiber->getState() == Fiber::TERM) {
                cb_fiber->reset(nullptr); // 重置cb
            } else {
                cb_fiber->m_state = Fiber::HOLD;
                cb_fiber.reset();   // 智能指针
            }
        } else {    // 进入这里的话,说明任务队列为空,开始idle协程
            if(is_active) {
                --m_activeThreadCount;
                continue;
            }
            // 如果调度器没任务的话,idle协程会不停的In和Out,
            // 在idle协程中什么也没做,具体业务留给子类
            // 如果idle协程结束了,说明一定是调度器停止了
            if(idle_fiber->getState() == Fiber::TERM) {
                std::cout << "[DEBUG]  idle fiber term" << std::endl;
                break;
            }

            ++m_idleThreadCount;
            idle_fiber->swapIn();   // 执行idle协程
            --m_idleThreadCount;
            if(idle_fiber->getState() != Fiber::TERM
                    && idle_fiber->getState() != Fiber::EXCEPT) {
                idle_fiber->m_state = Fiber::HOLD;
            }
        }
    }
}

void Scheduler::tickle() {
    std::cout << "[INFO]   tickle" << std::endl;
}

bool Scheduler::stopping() {
    MutexType::Lock lock(m_mutex);
    return m_autoStop && m_stopping
        && m_fibers.empty() && m_activeThreadCount == 0;
}

void Scheduler::idle() {
    std::cout << "[INFO]   idle" << std::endl;
    while(!stopping()) {
        sylar::Fiber::YieldToHold();
    }
}

// void Scheduler::switchTo(int thread) {

// }

// std::ostream& Scheduler::dump(std::ostream& os) {
//     return os;
// }

// SchedulerSwitcher::SchedulerSwitcher(Scheduler* target) {
//     m_caller = Scheduler::GetThis();
//     if(target) {
//         target->switchTo();
//     }
// }

// SchedulerSwitcher::~SchedulerSwitcher() {
//     if(m_caller) {
//         m_caller->switchTo();
//     }
// }

}

我在程序中加入了大量的调试信息方便调试,首先我们测试一下需要一个调度线程并且main线程参与其中的情况,其实就是只使用main线程来进行任务调度。

void test_fiber() {
    static int s_count = 2;
    std::cout << "[INFO]   test in fiber s_count = " << s_count << std::endl;

    // sleep(1);
    // if(-- s_count >= 0) {
    //     sylar::Scheduler::GetThis()->schedule(&test_fiber, syscall(SYS_gettid));
    // }
    
    std::cout << "[INFO]   test in fiber over, s_count = " << s_count << std::endl;
}

void test() {
    std::cout << "[INFO]   test in fiber over, s_count = " << 8 << std::endl;
}

int main(int argc, char** argv) {
    std::cout << "[INFO]   main" << std::endl;
    sylar::Scheduler sc(1, true, "test_Scheduler");
    sc.start();
    sleep(2);
    std::cout << "[INFO]   schedule" << std::endl;
    sc.schedule(&test);
    sc.schedule(&test_fiber);
    sc.stop();
    //for(;;){}
    std::cout << "[INFO]   schedule over" << std::endl;
    return 0;
}

在这个测试代码中我们添加了两个任务函数,其中一个会输出test in fiber over, s_count = 8
另一个会输出
test in fiber s_count = 2
test in fiber over, s_count = 2
下面我们看一下执行结果
[学习分享]----sylar服务器框架源码阅读--协程调度模块_第3张图片
这里可以看到没有打印after pthread_create这一条日志,这条日志添加到线程类的构造函数中去了,说明并没有额外创建线程。在scheduler下面打印了两行提醒其他线程有任务加入的日志,然后进入stop函数,然后m_rootFiber开始执行,创建空闲协程,创建用来执行任务的cb_fiber协程,然后就是那两个任务的执行,执行完之后,会进入idle协程,然后idle协程执行完毕,就会退出到主协程,然后stop结束,最后退出程序。

接下来我们不适用main线程,将use_caller设为false再从新执行以上测试程序。

int main(int argc, char** argv) {
    std::cout << "[INFO]   main" << std::endl;
    sylar::Scheduler sc(1, false, "test_Scheduler");
    sc.start();
    sleep(2);
    std::cout << "[INFO]   schedule" << std::endl;
    sc.schedule(&test);
    sc.schedule(&test_fiber);
    sc.stop();
    //for(;;){}
    std::cout << "[INFO]   schedule over" << std::endl;
    return 0;
}

运行结果如下
[学习分享]----sylar服务器框架源码阅读--协程调度模块_第4张图片
可以看到打印了after pthread_create这一条日志,说明额外创建了一个线程,也和上面一样将这两个任务执行完毕。接下来我们将test任务指定为main线程去执行,但是我们并没有让main线程参与调度,来看一下结果

int main(int argc, char** argv) {
    std::cout << "[INFO]   main" << std::endl;
    sylar::Scheduler sc(1, false, "test_Scheduler");
    sc.start();
    sleep(2);
    std::cout << "[INFO]   schedule" << std::endl;
    sc.schedule(&test, syscall(SYS_gettid));
    sc.schedule(&test_fiber);
    sc.stop();
    //for(;;){}
    std::cout << "[INFO]   schedule over" << std::endl;
    return 0;
}

结果如下
[学习分享]----sylar服务器框架源码阅读--协程调度模块_第5张图片
可以看到,这里一直再重复打印一样的日志,这说明有任务需要执行,但指定了main线程,实际工作的线程并不是main线程所以它就会一直提醒其他线程来处理这个业务,但是可怜的他并不知道,此时以没人会去搭理他,他便一直重复这一件事情。

接下来我们将使用main线程,并且额外再创建一个线程,在实现一下上面的任务。

int main(int argc, char** argv) {
    std::cout << "[INFO]   main" << std::endl;
    sylar::Scheduler sc(2, true, "test_Scheduler");
    sc.start();
    sleep(2);
    std::cout << "[INFO]   schedule" << std::endl;
    sc.schedule(&test, syscall(SYS_gettid));
    sc.schedule(&test_fiber);
    sc.stop();
    //for(;;){}
    std::cout << "[INFO]   schedule over" << std::endl;
    return 0;
}

结果如下
[学习分享]----sylar服务器框架源码阅读--协程调度模块_第6张图片
这次打印的调试信息有一点点多,哈哈,我写的调试信息太冗余了,可以看出来,程序正常执行了。
调度线程会在启动了stop方法后在没有任务时自动退出,下面我们不调用stop函数,不使用main线程,不指定任务的执行线程,并在main函数最后循环等待,看一下执行效果

int main(int argc, char** argv) {
    std::cout << "[INFO]   main" << std::endl;
    sylar::Scheduler sc(1, false, "test_Scheduler");
    sc.start();
    sleep(2);
    std::cout << "[INFO]   schedule" << std::endl;
    sc.schedule(&test);
    sc.schedule(&test_fiber);
    // sc.stop();
    for(;;){}
    std::cout << "[INFO]   schedule over" << std::endl;
    return 0;
}

效果图如下
[学习分享]----sylar服务器框架源码阅读--协程调度模块_第7张图片
可以看到,在执行完那两个任务之后,没有打印任何信息了,main线程在这里一直循环等待,而那个调度线程则是反复在idle与调度协程之间左右互搏,因为没有停止信号,所以idle并不会执行结束,只会在半路退回到调度协程,然后再进入idle协程。

总结

具体sylar协程调度器的流程讲解,代码讲解,结果调试都上上面给出。还有一些情况的调试信息我没有给出,比如只是用main线程调度,但是不执行stop函数,这样是没法启动调度的。我们可以根据自己的具体需求对这个调度器进行个性化修改。目前只能添加无参数无返回值的函数,在后面我想看看能不能设置成向golang一样的协程库。我能力有限,希望我可以做到。加油奥里给!

你可能感兴趣的:(linux,服务器,c++)