跨平台c++ Coroutine,仿unity3d实现
不多说,贴代码:
4 #include "stdafx.h" 5 #include <list> 6 #include <thread> 7 #include <chrono> 8 9 struct ICoroutine 10 { 11 virtual void reset(){} 12 virtual bool move_next(int & r, float & fv) { return false; } 13 virtual ~ICoroutine() {} 14 public: 15 float mWaitSeconds; 16 }; 17 18 template<typename T> 19 struct _IGenerator : public ICoroutine 20 { 21 T* _stack; 22 int _line; 23 _IGenerator() :_stack(0), _line(-1) {} 24 virtual void reset() 25 { 26 _line = -1; 27 } 28 void _push() { T* n = new T; *n = *static_cast<T*>(this); _stack = n; } 29 bool _pop() { if (!_stack) return false; T* t = _stack; *static_cast<T*>(this) = *_stack; t->_stack = 0; delete t; return true; } 30 ~_IGenerator() { while (_pop()); } 31 }; 32 33 #define $coroutine(NAME) struct NAME : public _IGenerator<NAME> 34 35 36 #define $begin virtual bool move_next(int& _rv, float& _rv2) { \ 37 if(_line < 0) _line=0; \ 38 $START: switch(_line) { case 0:; 39 40 #define $stop } _line = 0; if(_pop()) goto $START; return false; } 41 42 #define $restart(WITH) { _push(); _stack->_line = __LINE__; _line=0; WITH; goto $START; case __LINE__:; } 43 44 #define $yield(V) \ 45 do {\ 46 _line=__LINE__;\ 47 _rv = (V); return true; case __LINE__:;\ 48 } while (0) 49 50 #define $yield_f(V, V2) \ 51 do {\ 52 _line=__LINE__;\ 53 _rv = (V); _rv2 = V2; return true; case __LINE__:;\ 54 } while (0) 55 56 57 enum CoroutineState 58 { 59 CO_None, 60 CO_WaitForNextUpdate, 61 CO_WaitForSeconds, 62 CO_Exit 63 }; 64 65 class GScheduler 66 { 67 protected: 68 std::list<ICoroutine *> mActivityGList; 69 std::list<ICoroutine *> mWaitingGList; 70 std::list<ICoroutine *> mDeadingGList; 71 72 std::list<ICoroutine *> mGList; 73 74 void DestroyAllCoroutine() 75 { 76 std::list<ICoroutine *>::iterator iter; 77 for (iter = mGList.begin(); iter != mGList.end(); iter++) 78 { 79 ICoroutine * co = *iter; 80 delete co; 81 } 82 mGList.clear(); 83 mDeadingGList.clear(); 84 mWaitingGList.clear(); 85 mActivityGList.clear(); 86 } 87 public: 88 ~GScheduler() 89 { 90 DestroyAllCoroutine(); 91 } 92 93 94 template<typename T, typename T2> 95 ICoroutine* StartCoroutine(T2 * tObj) 96 { 97 ICoroutine * gen = new T(tObj); 98 mGList.push_back(gen); 99 mActivityGList.push_back(gen); 100 return gen; 101 } 102 103 void StopCoroutine(ICoroutine *) 104 { 105 } 106 107 void RestartAllCoroutine() 108 { 109 std::list<ICoroutine *>::iterator iter; 110 for (iter = mGList.begin(); iter != mGList.end(); iter++) 111 { 112 ICoroutine * co = *iter; 113 co->reset(); 114 mActivityGList.push_back(co); 115 } 116 } 117 118 void StopAllCoroutine() 119 { 120 mDeadingGList.clear(); 121 mWaitingGList.clear(); 122 mActivityGList.clear(); 123 } 124 void UpdateAllCoroutine(float dt) 125 { 126 std::list<ICoroutine *>::iterator iter, next; 127 for (iter = mWaitingGList.begin(); iter != mWaitingGList.end();iter = next) 128 { 129 next = iter; next++; 130 131 ICoroutine * co = *iter; 132 co->mWaitSeconds -= dt; 133 if (co->mWaitSeconds <= 0) 134 { 135 next = mWaitingGList.erase(iter); 136 mActivityGList.push_back(co); 137 } 138 } 139 140 for (iter = mActivityGList.begin(); iter != mActivityGList.end(); iter = next) 141 { 142 next = iter; next++; 143 144 ICoroutine * co = *iter; 145 146 bool isDeading = false; 147 148 int retValue = 0; 149 float retFValue = 0; 150 if (!co->move_next(retValue, retFValue)) 151 { 152 isDeading = true; 153 } 154 CoroutineState state = (CoroutineState)retValue; 155 if (state == CO_Exit) 156 { 157 isDeading = true; 158 } 159 else if (state == CO_WaitForNextUpdate) 160 { 161 162 } 163 else if (state == CO_WaitForSeconds) 164 { 165 float seconds = retFValue; 166 co->mWaitSeconds = seconds; 167 next = mActivityGList.erase(iter); 168 mWaitingGList.push_back(co); 169 } 170 171 if (isDeading) 172 { 173 next = mActivityGList.erase(iter); 174 mDeadingGList.push_back(co); 175 } 176 } 177 } 178 }; 179 //**********************************************************************************************************
//以下是测试程序: 180 class TestCoroutine1; 181 class TestCoroutine2; 182 class UIMain : public GScheduler 183 { 184 public: 185 UIMain() 186 { 187 } 188 void Enable() 189 { 190 RestartAllCoroutine(); 191 } 192 void Disable() 193 { 194 StopAllCoroutine(); 195 } 196 197 void Start() 198 { 199 ICoroutine *testCo = StartCoroutine<TestCoroutine1, UIMain>(this); 200 StartCoroutine<TestCoroutine2, UIMain>(this); 201 } 202 203 void Update(float dt) 204 { 205 UpdateAllCoroutine(dt); 206 } 207 208 void Test1(int v) 209 { 210 printf("Test1, v = %d\n", v); 211 } 212 void Test2(int v) 213 { 214 printf("Test2, v = %d\n", v); 215 } 216 }; 217 218 219 $coroutine(TestCoroutine1) 220 { 221 UIMain* n; 222 TestCoroutine1(UIMain* root = 0) : n(root) {} 223 int i = 0; 224 $begin 225 for (i = 0; i < 3; i++) 226 { 227 n->Test1(i); 228 $yield(CO_WaitForNextUpdate); 229 } 230 $yield(CO_Exit); 231 n->Test1(10); 232 $stop 233 }; 234 235 $coroutine(TestCoroutine2) 236 { 237 UIMain* n; 238 TestCoroutine2(UIMain* root = 0) : n(root) {} 239 int i = 0; 240 $begin 241 for (i = 3; i < 6; i++) 242 { 243 n->Test2(i); 244 $yield_f(CO_WaitForSeconds, 0.5f); 245 } 246 $yield(CO_Exit); 247 n->Test1(99); 248 $stop 249 }; 250 251 252 253 int _tmain(int argc, _TCHAR* argv[]) 254 { 255 UIMain uiMain; 256 257 uiMain.Enable(); 258 uiMain.Start(); 259 260 float dt = 0.05f; 261 float time = 0; 262 while (true) 263 { 264 uiMain.Update(dt); 265 std::this_thread::sleep_for(std::chrono::milliseconds((int)(dt*1000))); 266 time += dt; 267 if (time > 10) //10秒后重开协程 268 { 269 uiMain.Disable(); 270 uiMain.Enable(); //重新开始协程 271 time = 0; 272 } 273 } 274 return 0; 275 }