By default threads in M2000 uses Plan Sequential. Each thread get time to run all code inside. Another plan is the concurrent where execution of other threads can happen when execution of a thread is happen but not finished. We can use curly brackets { } for commands that we want to run sequential. Here in the examples we have a situation when we put two commands after Then in an If Then structure. Normaly after then and until the end of the line we call each command if condition is true. But in concurrent run the thread exit for a while to give time to other threads, and forget the rule! So we need a block { } to make them run as one command after "Then"
In these examples we use static variables for each thread, one for counting for exit the thread by erasing, and other to keep info about thread handler (a number from M2000 environment's task manager). Static variables can't exist with module local variables with same name . Also we see that definitions for threads are done inside a normal routine like Basic's Gosub Return (M2000 has subroutines also, Sub name() ...End Sub)
Try these examples using M2000 interpreter. Just write Edit A and copy the commands, then press Esc and write A to start it.
Newest version of M2000 not allow a static variable with same name as a local variable. But we can make as much threads we want with same static variable name (but each variable are static in one thread only). Control for error happen in Static command. Thread.Plan Sequential
' A=100 \\ NEW VERSION THIS PRODUCE ERROR, AT STATIC COMMAND
M=500
N=0
Gosub StartThreads
\\ using a thread for this task.
\\ we can exit by using mouse click or counting threads give zero
Task.Main 50 {
Threads
Refresh
if mouse or N=0 then exit
}
Threads
End
StartThreads:
For K=1 to 20 {
N++
Thread {
Print A*M, B \\ static A is used before any local A
A--
\\ changing thread plan we have a problem because
\\ thread this erase is executed without control from If
\\ so we need to use block { N-- : thread this erase }
\\ blocks are executed before task manager change thread
If A=0 then N-- : thread this erase
} as T execute static A=10, B=T
\\ Now we start thread
Thread T interval 100
}
Return
Second example show Concourrent Plan.
Thread.Plan Concurrent
M=500
N=0
Gosub StartThreads
\\ using a thread for this task.
\\ we can exit by using mouse click or counting threads give zero
Task.Main 50 {
Threads
Refresh
if mouse or N=0 then exit
}
Threads
End
StartThreads:
For K=1 to 20 {
N++
Thread {
Print A*M, B
A--
Print ">>", N
\\ block needed after then if concurrent plan used
If A=0 then { N-- : thread this erase }
} as T execute static A=10, B=T
\\ Now we start thread
Thread T interval random(10,100)
}
Return
Third example is like second one. We see a change of normal routine with a Sub Routine, also we see from threads we can call Display(), a module's subroutine. Subrutines uses modules namespace (so can see modules variables which is the same for all threads, but run in thread exexution object, so they can see static variables (these are per execution object). Defining variables in threads can be done, but it is proper to that temporary, using For this { } or calling a subroutine (any new definition erased in a subroutine, but no in a simple routine like one in two examples above). Threads are not erased by subroutines, they erased by using Threads Erase, or by using Thread N erase, or by the end of execution of thread parent. Because we can define threads in threads, these inner threads are not erased in exit of the parent module, so we use Threads Erase to erase them.
Thread.Plan Concurrent
M=500
N=0
StartThreads(20)
\\ using a thread for this task.
\\ we can exit by using mouse click or counting threads give zero
Task.Main 50 {
Threads
Refresh
if mouse or N=0 then exit
}
Threads
End
Sub Display()
Print ">>", N
End Sub
Sub StartThreads(Many)
For K=1 to Many {
N++
Thread {
Print A*M, B
A--
Display()
\\ block needed after then if concurrent plan used
If A=0 then { N-- : thread this erase }
} as T execute static A=10, B=T
\\ Now we start thread
Thread T interval random(10,100)
}
End Sub
Commands for threads, except Erase, Interval and Execute (this is an out of order execute, an execute when target thread is idle) are Hold, Restart.
In these examples we use static variables for each thread, one for counting for exit the thread by erasing, and other to keep info about thread handler (a number from M2000 environment's task manager). Static variables can't exist with module local variables with same name . Also we see that definitions for threads are done inside a normal routine like Basic's Gosub Return (M2000 has subroutines also, Sub name() ...End Sub)
Try these examples using M2000 interpreter. Just write Edit A and copy the commands, then press Esc and write A to start it.
Newest version of M2000 not allow a static variable with same name as a local variable. But we can make as much threads we want with same static variable name (but each variable are static in one thread only). Control for error happen in Static command. Thread.Plan Sequential
' A=100 \\ NEW VERSION THIS PRODUCE ERROR, AT STATIC COMMAND
M=500
N=0
Gosub StartThreads
\\ using a thread for this task.
\\ we can exit by using mouse click or counting threads give zero
Task.Main 50 {
Threads
Refresh
if mouse or N=0 then exit
}
Threads
End
StartThreads:
For K=1 to 20 {
N++
Thread {
Print A*M, B \\ static A is used before any local A
A--
\\ changing thread plan we have a problem because
\\ thread this erase is executed without control from If
\\ so we need to use block { N-- : thread this erase }
\\ blocks are executed before task manager change thread
If A=0 then N-- : thread this erase
} as T execute static A=10, B=T
\\ Now we start thread
Thread T interval 100
}
Return
Second example show Concourrent Plan.
Thread.Plan Concurrent
M=500
N=0
Gosub StartThreads
\\ using a thread for this task.
\\ we can exit by using mouse click or counting threads give zero
Task.Main 50 {
Threads
Refresh
if mouse or N=0 then exit
}
Threads
End
StartThreads:
For K=1 to 20 {
N++
Thread {
Print A*M, B
A--
Print ">>", N
\\ block needed after then if concurrent plan used
If A=0 then { N-- : thread this erase }
} as T execute static A=10, B=T
\\ Now we start thread
Thread T interval random(10,100)
}
Return
Third example is like second one. We see a change of normal routine with a Sub Routine, also we see from threads we can call Display(), a module's subroutine. Subrutines uses modules namespace (so can see modules variables which is the same for all threads, but run in thread exexution object, so they can see static variables (these are per execution object). Defining variables in threads can be done, but it is proper to that temporary, using For this { } or calling a subroutine (any new definition erased in a subroutine, but no in a simple routine like one in two examples above). Threads are not erased by subroutines, they erased by using Threads Erase, or by using Thread N erase, or by the end of execution of thread parent. Because we can define threads in threads, these inner threads are not erased in exit of the parent module, so we use Threads Erase to erase them.
Thread.Plan Concurrent
M=500
N=0
StartThreads(20)
\\ using a thread for this task.
\\ we can exit by using mouse click or counting threads give zero
Task.Main 50 {
Threads
Refresh
if mouse or N=0 then exit
}
Threads
End
Sub Display()
Print ">>", N
End Sub
Sub StartThreads(Many)
For K=1 to Many {
N++
Thread {
Print A*M, B
A--
Display()
\\ block needed after then if concurrent plan used
If A=0 then { N-- : thread this erase }
} as T execute static A=10, B=T
\\ Now we start thread
Thread T interval random(10,100)
}
End Sub
Commands for threads, except Erase, Interval and Execute (this is an out of order execute, an execute when target thread is idle) are Hold, Restart.
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
You can feel free to write any suggestion, or idea on the subject.