107 lines
3.4 KiB
ReStructuredText
107 lines
3.4 KiB
ReStructuredText
.. _threads:
|
|
|
|
|
|
========================
|
|
Threads
|
|
========================
|
|
|
|
.. index::
|
|
single: Threads
|
|
|
|
Squirrel supports cooperative threads(also known as coroutines).
|
|
A cooperative thread is a subroutine that can suspended in mid-execution and provide a value to the
|
|
caller without returning program flow, then its execution can be resumed later from the same
|
|
point where it was suspended.
|
|
At first look a Squirrel thread can be confused with a generator, in fact their behaviour is quite similar.
|
|
However while a generator runs in the caller stack and can suspend only the local routine stack a thread
|
|
has its own execution stack, global table and error handler; This allows a thread to suspend nested calls and
|
|
have it's own error policies.
|
|
|
|
------------------
|
|
Using threads
|
|
------------------
|
|
|
|
.. index::
|
|
single: Usign Threads
|
|
|
|
Threads are created through the built-in function 'newthread(func)'; this function
|
|
gets as parameter a squirrel function and bind it to the new thread objecs(will be the thread body).
|
|
The returned thread object is initially in 'idle' state. the thread can be started with the function
|
|
'threadobj.call()'; the parameters passed to 'call' are passed to the thread function.
|
|
|
|
A thread can be be suspended calling the function suspend(), when this happens the function
|
|
that wokeup(or started) the thread returns (If a parametrer is passed to suspend() it will
|
|
be the return value of the wakeup function , if no parameter is passed the return value will be null).
|
|
A suspended thread can be resumed calling the funtion 'threadobj.wakeup', when this happens
|
|
the function that suspended the thread will return(if a parameter is passed to wakeup it will
|
|
be the return value of the suspend function, if no parameter is passed the return value will be null).
|
|
|
|
A thread terminates when its main function returns or when an unhandled exception occurs during its execution.::
|
|
|
|
function coroutine_test(a,b)
|
|
{
|
|
::print(a+" "+b+"\n");
|
|
local ret = ::suspend("suspend 1");
|
|
::print("the coroutine says "+ret+"\n");
|
|
ret = ::suspend("suspend 2");
|
|
::print("the coroutine says "+ret+"\n");
|
|
ret = ::suspend("suspend 3");
|
|
::print("the coroutine says "+ret+"\n");
|
|
return "I'm done"
|
|
}
|
|
|
|
local coro = ::newthread(coroutine_test);
|
|
|
|
local susparam = coro.call("test","coroutine"); //starts the coroutine
|
|
|
|
local i = 1;
|
|
do
|
|
{
|
|
::print("suspend passed ("+susparam+")\n")
|
|
susparam = coro.wakeup("ciao "+i);
|
|
++i;
|
|
}while(coro.getstatus()=="suspended")
|
|
|
|
::print("return passed ("+susparam+")\n")
|
|
|
|
the result of this program will be::
|
|
|
|
test coroutine
|
|
suspend passed (suspend 1)
|
|
the coroutine says ciao 1
|
|
suspend passed (suspend 2)
|
|
the coroutine says ciao 2
|
|
suspend passed (suspend 3)
|
|
the coroutine says ciao 3
|
|
return passed (I'm done).
|
|
|
|
|
|
the following is an interesting example of how threads and tail recursion
|
|
can be combined.::
|
|
|
|
function state1()
|
|
{
|
|
::suspend("state1");
|
|
return state2(); //tail call
|
|
}
|
|
|
|
function state2()
|
|
{
|
|
::suspend("state2");
|
|
return state3(); //tail call
|
|
}
|
|
|
|
function state3()
|
|
{
|
|
::suspend("state3");
|
|
return state1(); //tail call
|
|
}
|
|
|
|
local statethread = ::newthread(state1)
|
|
|
|
::print(statethread.call()+"\n");
|
|
|
|
for(local i = 0; i < 10000; i++)
|
|
::print(statethread.wakeup()+"\n");
|
|
|