File: doc_adv_coroutine.h

package info (click to toggle)
angelscript 2.38.0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,736 kB
  • sloc: cpp: 77,114; asm: 2,017; makefile: 666; xml: 253; javascript: 42; ansic: 26; python: 22; sh: 7
file content (106 lines) | stat: -rw-r--r-- 3,608 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**

\page doc_adv_coroutine Co-routines

Co-routines is a way to allow multiple execution paths in parallel, but without the hazards of pre-emptive scheduling in 
\ref doc_adv_concurrent "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 \ref doc_addon_ctxmgr 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 \ref 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 
   \ref doc_datatypes_funcptr "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:

\code
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);
  }
}
\endcode

The yield function is even simpler:

\code
void Yield()
{
  asIScriptContext *ctx = asGetActiveContext();
  if( ctx )
  { 
    // Suspend the context so the next co-routine can be resumed
    ctx->Suspend();
  }
}
\endcode

A basic control algorithm might look like this:

\code
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);
    }
  }
}
\endcode


\see \ref doc_addon_ctxmgr, \ref doc_samples_corout, \ref doc_adv_concurrent






*/