# 概述 定义了协程、线程阻塞、唤醒的操作,由`struct Rutex`使用。 `struct Rutex`是libgo的同步系统重要结构,因为定义了协程阻塞、唤醒的操作,才保证了协程锁(仅阻塞协程)的实现。 # 代码分析 switcher由4个类组成,分别是`RoutineSwitcherI`,`PThreadSwitcher`,`LibgoSwitcher`和`RoutineSyncPolicy` ## 类图 ![image-20230201092839844](./img/libgo-switcher-class-uml.png) ## RoutineSwitcherI ```c++ struct RoutineSwitcherI { public: virtual ~RoutineSwitcherI() { valid_ = false; } // 把当前routine标记为休眠状态, 但不立即休眠routine // 如下两种执行顺序都必须支持: // mark -> sleep -> wake(其他线程执行) // mark -> wake(其他线程执行) -> sleep virtual void mark() = 0; // 在routine中调用的接口,用于休眠当前routine // sleep函数中切换routine执行权,当routine被重新唤醒时函数才返回 virtual void sleep() = 0; // 在其他routine中调用,用于唤醒休眠的routine // @return: 返回唤醒成功or失败 // @要求: 一次sleep多次wake,只有其中一次wake成功,并且其他wake不会产生副作用 virtual bool wake() = 0; // 判断是否在协程中 (子类switcher必须实现这个接口) //static bool isInRoutine(); // 返回协程私有变量的switcher (子类switcher必须实现这个接口) //static RoutineSwitcherI & clsRef() private: bool valid_ = true; public: inline bool valid() const { return valid_; } }; ``` ## PThreadSwitcher ```c++ struct PThreadSwitcher : public RoutineSwitcherI { public: PThreadSwitcher() { // printf("PThreadSwitcher threadid=%d\n", (int)syscall(SYS_gettid)); } virtual ~PThreadSwitcher() { // printf("~PThreadSwitcher threadid=%d\n", (int)syscall(SYS_gettid)); } virtual void mark() override { std::unique_lock lock(mtx_); waiting_ = true; } virtual void sleep() override { std::unique_lock lock(mtx_); while (waiting_) cond_.wait(lock); } virtual bool wake() override { std::unique_lock lock(mtx_); if (!waiting_) return false; waiting_ = false; cond_.notify_one(); return true; } static bool isInRoutine() { return true; } static RoutineSwitcherI & clsRef() { static thread_local PThreadSwitcher pts; return static_cast(pts); } private: std::mutex mtx_; std::condition_variable cond_; bool waiting_ = false; }; ``` ## LibgoSwitcher ```c++ struct LibgoSwitcher : public libgo::RoutineSwitcherI { public: virtual void mark() override { entry_ = Processer::Suspend(); } virtual void sleep() override { Processer::StaticCoYield(); } // 在其他routine中调用,用于唤醒休眠的routine // @return: 返回唤醒成功or失败 // @要求: 一次sleep多次wake,只有其中一次wake成功,并且其他wake不会产生副作用 virtual bool wake() override { return Processer::Wakeup(entry_); } // 判断是否在协程中 (子类switcher必须实现这个接口) static bool isInRoutine() { return Processer::IsCoroutine(); } // 返回协程私有变量的switcher (子类switcher必须实现这个接口) static libgo::RoutineSwitcherI & clsRef() { return static_cast( *(LibgoSwitcher*)Processer::GetCurrentTask()->extern_switcher_); } private: Processer::SuspendEntry entry_; }; ``` ## RoutineSyncPolicy