Accessing single resources during multi-tasking

hippy

Technical Support
Staff member
#1
Sometimes multiple tasks of a multi-tasking program will desire access to a single resource of the PICAXE; serial, LCD, I2C, PWMOUT, etc. If two or more tasks try to access the same resource simultaneously they can often trample over each other and the outcome will not be as intended.

For example, if we wish to output five '0' from one task and five '1' from another, and run the following program on a real PICAXE chip or in the PE6 simulator -
Code:
#Picaxe 08M2
#Terminal 4800
#SimTask ALL

Start0:
  Do
    For b0 = 1 To 5
      Sertxd( "0" )
    Next
   Loop

Start1:
  Do
    For b1 = 1 To 5
      Sertxd( "1" )
    Next
  Loop
The output isn't our desirable '00000111110000011111' etc but '0101010101' etc.

It is possible to take sole control of a resource by suspending other tasks which use that resource but that means knowing which tasks use that resource, is a brute force approach if the other tasks are not imminently going to use that resource - that task gets suspended when there is no good reason to suspend it, and there can sometimes be issues where multiple tasks are suspending and resuming each other.

A better approach is to have each task ask for access to the resource only when it wants to use it, and only let that task proceed once it has access to the resource. When finished with a resource the task can then release the resource for other tasks to use.

In this example we create an 'owner' variable which indicates who has taken ownership of the resource and add 'GrabResource' and 'ReleaseResource' routines to control access to it. Note there must be an initial 'Gosub ReleaseResource' in one, and only one, of the tasks -
Rich (BB code):
#Picaxe 08M2
#Terminal 4800
#SimTask ALL

Symbol owner = b27

Start0:
  Gosub ReleaseResource
  Do
    Gosub GrabResource
    For b0 = 1 To 5
      Sertxd( "0" )
    Next
    Gosub ReleaseResource
  Loop

Start1:
  Do
    Gosub GrabResource
    For b1 = 1 To 5
      Sertxd( "1" )
    Next
    Gosub ReleaseResource
  Loop

ReleaseResource:
  owner = $FF
  Return

GrabResource:
  Do
    If owner = $FF Then
      owner = task
    End If
  Loop Until owner = task
  Return
Task 0 now grabs the resource while it outputs its five '0' and Task 1 grabs the resource while it outputs its five '1'.

We could add additional tasks using the same basic task structure without having to change anything else; no need to go through and add or adjust SUSPEND and RESUME statements, there's no chance we will miss one or introduce other problems.
 
Last edited:

hippy

Technical Support
Staff member
#2
Note that in the above code, the output starts with five '1' rather than five '0'. This is because Task1 has got itself waiting for the resource before Task 0 tries to grab the resource.

Task 0 can be forced to be the first to grab the resource by putting the 'Gosub ReleaseResource' at the start of Task 1.

Alternatively the 'Gosub ReleaseResource' at the start of Task 0 can be replaced with 'owner = task' or 'owner = 0'.

In fact, any task can force itself, or any other, to be the first to grab a resource by setting 'owner' this way.

Note however that no tasks will be able to grab the resource until the task which is initially assigned as owner has executed a 'Gosub GrabResource'.
 
Top