Multiple Instances of a Task

Started by Don Kinzer October 6, 2005
Has anyone ever tried to invoke multiple instances of a given task
so they are running "at the same time"? I tried the code below
which seems like it ought to work. However, it only runs if I
comment out the second and third task invocations. I have separate
a task stack for each invocation - an obvious requirement. I tried
different stack sizes; I think the value I used should be plenty.
Perhaps I'm missing something else.

Dim sem(1 to 3) as Boolean
Dim ioSem as Boolean
Dim ts1(1 to 50) As Byte
Dim ts2(1 to 50) As Byte
'Dim ts3(1 to 50) As Byte

Sub Main()
ioSem = false
sem(1) = false
sem(2) = false
sem(3) = false
CallTask "MyTask", ts1
CallTask "MyTask", ts2
' CallTask "MyTask", ts3
Do
Loop
End Sub

Sub MyTask()
Dim i as Byte
Dim myID as Byte

' find out which invocation this is by
' getting the next available semaphore
myID = 0
For i = 1 to 3
If (Semaphore(sem(i))) Then
myID = i
Exit For
End If
Next

For i = 1 to 20
' get semaphore for I/O to avoid overlapping
Do
Loop Until Semaphore(ioSem)
Debug.Print "T-";
Debug.Print CStr(myId);
Debug.Print ":";
Debug.print CStr(i)
ioSem = false
Call Delay(0.5 * CSng(i))

' see if it is time to exit
If (i = myID * 3) Then
Exit For
End If
Next

' indicate that the task is done
Debug.Print "T-";
Debug.Print CStr(myId);
Debug.Print " done"
End Sub



--- In basicx@basi..., "Don Kinzer" <dkinzer@e...> wrote:
> Has anyone ever tried to invoke multiple instances of a given task
> so they are running "at the same time"?

What an interesting idea! Just to see where the problem is, did you
try to name the tasks slightly differently (i.e. Tast1, Task2,
Task3, each with its own separate version of the code) and then see
if it runs as expected. This would eliminate all but name as the
culprit.

I am sure you already thought of this.

I admit that I did not look as hard at the code as I should
regarding the semaphores, but could the semaphores not be shared
properly?

I would have just assumed that there would be a collision somewhere
between the tasks, but with their own stacks etc., upon further
consideration I would think that a collision is impossible. I
assume that when a task is active, the hardware loads the next
instruction based on its IP (maybe) residing in its own stack.
Therefore each task has no logical or physical connection to any
other task except through the operating system. Consequently I
would expect that the same code COULD be used for separate tasks and
thereby save code space.

It may give us a clue about the internal functions of the operating
system if there is some other collision occuring. Maybe something
about a task is not as insulated from the rest as it should be. I
woud assume that it would be a shortcut that was taken to save
memory because they never thought of the possibility of multiple
instances of the same task.

What are your ideas about why this is not working?

-Tony


--- In basicx@basi..., "arhodes19044" <spamiam@c...> wrote:
> Just to see where the problem is, did you try to name the tasks
> slightly differently ...

I hadn't done so previously. Doing so produced the same result. As
you suggested, this eliminated as the cause of the problem the fact
that the same task was being invoked multiple times.

> ... could the semaphores not be shared properly?

The array of semaphores was being used in this experiment solely as
a way to allow the several instances to obtain some sort of
identifier. When an instance of the task begins running it indexes
through the semaphore array trying to get a semaphore. The index at
which it is successful is used as an ID for the instance. The only
purpose of the ID in this experiment is to identify in the output
which instance of the task is running.

In researching this further, I discovered that the culprit all along
was that the task stacks were too small. It turns out that 60
doesn't work, 65 does.

I've added some additional commentary to the test file and placed it
on my server for those that want to experiment with it. You can get
it from:

http://www.kinzers.com/don/BX24/TaskTest.bas

Don



Don Kinzer wrote:

> In researching this further, I discovered that the culprit all along
> was that the task stacks were too small. It turns out that 60
> doesn't work, 65 does.

I haven't had time to get to your question until now. Running the
program through the "bxDism" utility produces a required task stack size
of 63 bytes which is in line with your result. Your original size was 50
which did look kinda small for what you were attempting to do - any time
you use debug.print and/or strings your stack is going to be quite large.

Mike
http://home.austin.rr.com/perks/basicx/bxDism/


--- In basicx@basi..., Mike Perks <basicx@a...> wrote:
> Running the program through the "bxDism" utility produces a
> required task stack size of 63 bytes ...

So it does. I had run bxDism on the program earlier but, for whatever
reason, I thought that it indicated 48 bytes (That's why I had the
stack size set to 50).



Perhaps obvious, a one-line task makes a VB-like timer. When the task
completes, its stack's first byte becomes value bxTaskHalted. It can be
reused, but a second concurrent instance requires another 17-byte stack.

dim bTimerTaskStack(1 to 17) as byte, sPeriod as single

sub TimerTask()
call sleep(sPeriod)
end sub

'start a timer
sPeriod = 1.5
CallTask "TimerTask", bTimerTaskStack

'test for task completion
do until bTimerTaskStack(1) = bxTaskHalted '1.5 seconds later
loop
Tom