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:
- The co-routine itself, which is just an instance of the asIScriptContext object. Each co-routine will have its own context object that holds the callstack of the co-routine.
- A function that will permit the script to create, or spawn, new co-routines. This function will need to be able to refer to starting function of the new co-routine. This reference can be done by name, or perhaps more elegantly with a function pointer. Once invoked this function will instanciate the new context, and prepare it with the starting function.
- A function that will permit a co-routine to yield control to the next co-routine. This function will simply suspend the current context so the next co-routine can be resumed.
- A simple control algorithm for the co-routines. This can just be a loop that will iterate over an array of co-routines, i.e. contexts, until all of them have finished executing. When a new co-routine is created it is simply appended to the array to be picked up when the current co-routine yields the control.
A simple implementation of the function that spawns a new co-routine may look like this:
void CreateCoRoutine(string &func)
{
if( ctx )
{
string decl = "void " + func + "()";
if( funcPtr == 0 )
{
ctx->
SetException((
"Function '" + decl +
"' doesn't exist").c_str());
return;
}
coroutines.push_back(coctx);
}
}
The interface to the virtual machine.
Definition: angelscript.h:2764
virtual asIScriptFunction * GetFunction(asUINT stackLevel=0)=0
Returns the function at the specified callstack level.
virtual int Prepare(asIScriptFunction *func)=0
Prepares the context for execution of the function.
virtual asIScriptEngine * GetEngine() const =0
Returns a pointer to the engine.
virtual int SetException(const char *info, bool allowCatch=true)=0
Sets an exception, which aborts the execution.
The engine interface.
Definition: angelscript.h:1125
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
virtual asIScriptContext * CreateContext()=0
Creates a new script context.
The interface for a script function description.
Definition: angelscript.h:4031
virtual const char * GetModuleName() const =0
Returns the name of the module where the function was implemented.
virtual asIScriptFunction * GetFunctionByDecl(const char *decl) const =0
Returns the function by its declaration.
AS_API asIScriptContext * asGetActiveContext()
Returns the currently active context.
The yield function is even simpler:
void Yield()
{
if( ctx )
{
}
}
virtual int Suspend()=0
Suspends the execution, which can then be resumed by calling Execute again.
A basic control algorithm might look like this:
std::vector<asIScriptContext *> coroutines;
void Execute()
{
int n = 0;
while( coroutines.size() > 0 )
{
int r = coroutines[n]->Execute();
{
if( ++n == coroutines.size() )
n = 0;
}
else
{
coroutines[n]->Release();
coroutines.erase(n);
}
}
}
@ asEXECUTION_SUSPENDED
The execution is suspended and can be resumed.
Definition: angelscript.h:481
- See also
- Context manager, Co-routines, Concurrent scripts