AngelScript
|
Co-routines is a way to allow multiple execution paths in parallel, but without the hazards of pre-emptive scheduling in multithreading where one thread can be suspended at any moment so another can resume. Because co-routines always voluntarily suspend themselves in favor of the next co-routine, there is no need to worry about atomic instructions and critical sections.
Co-routines are not natively built-into the AngelScript library, but it can easily be implemented from the application side. In fact, the Context manager add-on already provides a default implementation for this.
To implement your own version of co-routines you will need a couple of pieces:
A simple implementation of the function that spawns a new co-routine may look like this:
void CreateCoRoutine(string &func) { asIScriptContext *ctx = asGetActiveContext(); if( ctx ) { asIScriptEngine *engine = ctx->GetEngine(); string mod = ctx->GetFunction()->GetModuleName(); // We need to find the function that will be created as the co-routine string decl = "void " + func + "()"; asIScriptFunction *funcPtr = engine->GetModule(mod.c_str())->GetFunctionByDecl(decl.c_str()); if( funcPtr == 0 ) { // No function could be found, raise an exception ctx->SetException(("Function '" + decl + "' doesn't exist").c_str()); return; } // Create a new context for the co-routine asIScriptContext *coctx = engine->CreateContext(); coctx->Prepare(funcPtr); // Add the new co-routine context to the array of co-routines coroutines.push_back(coctx); } }
The yield function is even simpler:
void Yield() { asIScriptContext *ctx = asGetActiveContext(); if( ctx ) { // Suspend the context so the next co-routine can be resumed ctx->Suspend(); } }
A basic control algorithm might look like this:
std::vector<asIScriptContext *> coroutines; void Execute() { int n = 0; while( coroutines.size() > 0 ) { // Resume the co-routine int r = coroutines[n]->Execute(); if( r == asEXECUTION_SUSPENDED ) { // Resume the next co-routine if( ++n == coroutines.size() ) n = 0; } else { // The co-routine finished so let's remove it coroutines[n]->Release(); coroutines.erase(n); } } }