User Tools

Site Tools


k20:k20.6:start

20.6.0 Task

Imagine the following situation:

In a programme, time-intensive computations are executed as a subtask in a procedure P. This means that the interpreter is bound while P is being executed. During the time P is being executed, it does not enter the event loop, which can be regarded as the interpreter's rest mode. There it waits for external events, such as a click on a button. This means - while P is being executed - that the GUI of the process is frozen!

In order to still be able to react promptly to an event, there are two possibilities:

  • You force the entry into the event loop with the wait statement at suitable places in the source code.
  • You outsource the procedure P to a task as a background process. This means that the processing of P is executed by another instance of the interpreter in another process. Your “main interpreter” (which looks after the GUI of the process) is in idle mode and can react immediately to user input and the results coming in from the task.

In Gambas, tasks are also used, for example in the gb.form component, to generate a file preview. The trick is this: while the file preview is being generated in a task, the main programme can still interact with the user. It is not in a time-consuming routine and the event loop in the main program runs normally.

  • The class Task exists in the component gb and is thus part of the interpreter.
  • The terms Task and background process are used synonymously in this chapter - clearly distinguished from the Task object as an instance of a Task class to be written by itself, which inherits from the class Task (gb) via the instruction 'INHERITS Task'.

A task represents a copy of the parent process (fork → http://de.wikipedia.org/wiki/Fork_%28Unix%29) and runs as an independent process with its own process number completely independently of the calling parent process. Passed variables, for example, can therefore be changed independently in the task without the parent (parent) process noticing anything. Of course, the same applies in the other direction.

In this chapter, in addition to the properties, methods and events of the class Task (gb), you will be introduced to projects that show their use.

20.6.0.1 Properties

The Task class has three properties:

PropertyData typeDescription
HandleIntegerReturns the process number (PID) of the background process (task).
RunningBooleanReturns True if the specified background process is running.
ValueVariantReturns the function value of the Main() function of the background process. If an error occurred in the background process, an error is triggered which can be read and evaluated via Task.Value.

Table 20.6.0.1.1 : Properties of the class Task

  • After the function value of the Main() method has been returned, the background process is automatically terminated and you can read the function value (data type Variant) in the Task_Kill() event via the Task.Value property.
  • An error in the background process also triggers the Task_Kill() event and not - which would be obvious - the Error(Data AS String) event, because an error in the background process also ends the background process immediately.
  • Error information can also be read out via the property Task.Value.

20.6.0.2 Methods

The Task class has only two methods:

  • Task.Stop: The active task as background process is stopped!
  • Task.Wait: Wait for the active background process to end.

20.6.0.3 Events

In the Task class, these three events are declared:

EventDescription
Read(Data As String)The event is triggered when the task outputs data (data type String) to its standard output. Normally, the data is output line by line; unless the task uses the FLUSH statement without an argument. The task standard output can also be used to send task status information to the parent process.
Error(Data As String)The event is triggered when the task outputs data on its error output.
Kill()The event is triggered when the active task has been terminated as a background process.

Table 20.6.0.3.1 : Events of the Class Task

The event Error(Data AS String) is only triggered if data was written to the standard error output in the background process, for example with the ERROR command!

Contrary to what the event Task_Kill() suggests, the event is not triggered when the task object is destroyed, but when the task process is terminated. Terminated here means:

  • The task was stopped by the method Task.Stop or.
  • after the end of the Main() method, the Task is automatically terminated.

It is important to emphasise the difference between Task as a background process - in which the Task code is executed - and Task object, which exists in the parent Gambas process. The Task object allows you to communicate with the Task as long as the Task exists. The Task object, however, 'survives' the end of the background process so that you can still read the function value of the Main() function (data type Variant) via the Task.Value property or other properties after it ends.

20.6.0.4 Task as background process in Gambas

To have a task processed in the background in a task you need to:

  • first create a class with a freely selectable class name, which inherits the class Task → Task class,
  • then define in the Task class a public Main() method without argument, which describes the task to be processed and
  • then create an instance of the Task class in the (main) programme to start a new task. In addition, specify a suitable event name if, for example, you want to catch and react to the Read(Data AS String), the Error(Data AS String) or the Kill() event.

The question of whether a task is necessarily started as a background process when a task object is created can be answered like this:

  • If a Task object is created, the start of an associated background process is immediately scheduled. However, the task is not actually started until the next execution of the event loop.
  • Within the Task, the Main() method of the Task class is executed. If the function value of the Main() function has been returned, then the task is automatically terminated! However, the Task object in the main process is retained! *

20.6.0.5 Task Priority

You can change the priority of a background process via the property Application.Priority (data type Integer) → chapter 20.11 Class Application (gb). The default priority has the value 0.

To increase the priority of a background process (values -1 to -20), root rights are required, which you do not need to decrease the priority (values 1 to 19).

' Gambas class file
 
Inherits Task
 
Public Function Main() As Variant
  Dim aTagesListe As String[]
 
  Application.Priority = 10 '-- Process priority for the task
 
  aTagesListe = Split("Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", ",")
  Return aTagesListe[WeekDay(Now())]
 
End

20.6.0.6 Interactive Process Communication

Data transfer between a task as a background process and the parent (parent) process is only uni-directional - i.e. in one direction - in the Task (gb) class:

(A) Programme → Task

In this direction, you can give the task one-time arguments as start values. To do this, you must define public variables in the task class - here MyTask.class - in order to assign suitable (start) values to them in the programme immediately after creating the task.

MyTask.class:

  Public iWaitTime As Integer '-- Start-Argument für die Wartezeit zwischen den drei Anzeigen

FMain.class:

Private hTask As MyTask
 
Public Sub btnTaskStart_Click()
  If hTask = NULL then hTask = New MyTask As "MyTask" ' = Task-Klassen-Name
  hTask.iWaitTime = 3 ' Wertzuweisung für globale Variable in der Klasse MyTask
  ...
 
End

You can see another approach to passing arguments here:

MyTask.class:

Public Sub _new({Matrix} As Matrix, Row As Integer)
  $hMatrix = {Matrix}
  $iRow = Row
End

FMain.class:

Public Sub Main()
  Dim iRow, iCol As Integer
  Dim hDeterminante As TaskMinors
 
  ...
  For iCol = 0 To $hMatrix.Width - 1
      hDeterminante = New TaskMinors($hMatrix, iRow) As "TaskMinors"
      hDeterminante.Tag = iRow
      Inc $iTasks '-- Den (internen) Zähler für die gestarteten Tasks erhöhen
  Next
 
  ...
End

(B) Task → Programme

The type of data transfer is determined by whether a (function) value is only returned once from the task or whether data is permanently transferred from the task to the main process (clocked, random). If you need data from the running task, you must read this data sent to the standard outputs in the event Task_Read(Data As String) or in the event Task_Error(Data As String) via the PRINT or ERROR command in the Main() method. Note: In the second case, only data of the data type String is allowed.

In the projects presented you will find the different implementations of inter-process communication (IPC).

For a permanent data transmission Task → Programme of data with native data type, Tobias Boege has developed serialisation and deserialisation functions, which are presented in a special project.

20.6.0.7 Project 1

The task to be worked on in project 1 does not sound spectacular: With the start of the programme, an analogue clock is to be displayed and parallel to this, the day of the week is calculated and displayed from the current date via a task. Since you need the function value of the Main() function from the task - which is its only purpose in life - once, you can read out the property Task.Value after the background process has ended.

The source code for the Task class DayTask.class is given in full, while only relevant sections of the class FMain.class are presented:

' Gambas class file
 
Inherits Task
 
Public Function Main() As Variant
  Dim aTagesListe As String[]
 
  aTagesListe = Split("Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", ",")
  Return aTagesListe[WeekDay(Now())] '-- Return of the day of the week
 
End

In this class, the day of the week is calculated from the current date and returned as a function value from the Main method.

In the programme, a task is created in the procedure TaskRun():

  ' Gambas class file
 
  Private $hTask As DayTask
 
  Public Sub Form_Open()
    ...
'-- Creating a Task: Task Object and Task Process
    TaskRun()
 
  End
 
  Private Sub TaskRun()
 
'-- Create a new task object - Object name = Object event name: DayTask
    If $hTask = Null Then $hTask = New DayTask As "DayTask"
    Repeat
      Wait 0.001
    Until $hTask <> Null
 
  End
 
  Public Sub DayTask_Kill()
    Dim DayOfWeek As String
    Dim sErrorMessage As String
 
'-- Save process return value. Alternative: Last.Value
    Try DayOfWeek = $hTask.Value
    If Not Error Then
       lblDayOfWeek.Text = DayOfWeek
    Else
       sErrorMessage = "Error!" & gb.NewLine
       sErrorMessage &= Error.Where & gb.NewLine
       sErrorMessage &= Error.Text
       Message.Error(sErrorMessage)
       lblDayOfWeek.Text = "Task error"
    Endif
 
  End
...

The analogue clock is displayed and below it the weekday calculated once in the task for the current date - if no error occurred in the task:

Figure 20.6.0.7.1: Display of time and weekday

You can create an error quite easily by using a semicolon instead of the correct separator comma, for example:

  aTagesListe = Split("Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", ";")

The display changes in the lower part because in the procedure 'Public Sub DayTask_Kill()' the error is detected and documented:

Figure 20.6.0.7.2: Display of time and error message

You can see very clearly again in the last case that with the creation of the task after the fork into two independent processes, the clock runs completely independent of the task and its return value.

Download

Chapter & Project

Download

The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k20/k20.6/start.txt · Last modified: 22.10.2023 by emma

Page Tools