Co-routines

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 + "()"; 
    int funcId = engine->GetModule(mod.c_str())->GetFunctionIdByDecl(decl.c_str());
    if( funcId < 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(funcId);

    // 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);
    }
  }
}

See also:
Context manager, Co-routines, Concurrent scripts

Generated on Mon Dec 6 23:08:45 2010 for AngelScript by  doxygen 1.5.9