Concurrency with Multiple Threads

Started by reaper, Mar 01, 2015, 06:21 PM

Previous topic - Next topic

reaper

I have created two threads, one each for addition and subtraction. I want them to run simultaneously, what are the possible ways for achieving concurrency?
function onScriptLoad()
{
local coro1 = newthread(add);
local coro2 = newthread(sub);
local addition=coro1.call(0);
local subtraction=coro2.call(50);
local i=1;
do
 {
 print("suspend passed ("+addition+")\n");
 print("suspend passed ("+subtraction+")\n");
 if(coro1.getstatus()=="suspended")
 addition= coro1.wakeup("Addition started "+i);
 if(coro2.getstatus()=="suspended")
 subtraction= coro2.wakeup("Subtraction started "+i);
 ++i;
 }while(coro1.getstatus()=="suspended"||coro2.getstatus()=="suspended");
}
x <- 0;
y <- 50;
function add(x)
{
 while(x<50)
 {
 x=x+5;
 print(x);
 if(x==25)
 local ret = suspend("addition suspended");
 }
}

function sub(y)
{
while(y>0)
 {
 y=y-5;
 print(y);
 if(y==25)
 local ret = suspend("subtraction suspended");
 }
}

.

You haven't read the documentation. The function which you create as a co-routine/thread doesn't suspend and therefore there's nothing to resume.

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

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");
.

.

#2
Quote from: reaper on Mar 01, 2015, 06:21 PMI want them to run simultaneously

Also, this isn't true threading. These are co-routines. What that means that you can't really run two things at once, simultaneously. You run/resume one and then when that pauses or finishes you run/resume the other and so on.

Also, if you don't have to pass a message or any parameter that you don't use to a co-routine when you resume it. Instead of declaring those x, y variables globally you could exchange that with the co-routine when you resume it.
.