SYNAPSE

Az ütemezés vezérlése

Az ütemezés vezérlése

A taskok ütemezéséhez gazdag eszköztárat biztosít a nyelv, amelyek tkp. a task típus predefinit mûveletei.

Egy task kétféleképpen hozható létre. A start utasítás létrehoz egy, az argumentumának megfelelõ típusú taskot és be is ütemezi azt. Az utasításnak több argumentuma is lehet. A create utasítás létrehoz egy az argumentumának megfelelõ típusú taskot, de nem végzi el annak beütemezését. Az utasításnak csak egy argumentuma lehet, és egy byte típusú task azonosítót ad meg értékül. Ezzel az értékkel késõbb hivatkozhatunk az adott taskra. Mindkét utasítás argumentumaiként task unitok azonosítónevei szerepelhetnek.

Egy task a saját azonosítójára a self alapszóval hivatkozhat. Ha egy T1 task létrehoz egy T2 taskot, akkor a T1 a T2 szülõje, míg a T2 a T1 gyereke. A szülõ task azonosítójára a parent, az utolsóként létrehozott gyerek task azonosítójára a child alapszóval hivatkozhatunk.

Egy task beütemezése a végrehajtási sorba való bekerülését jelenti. Egy beütemezett task aktív, ha végrehajtás alatt van. A suspend utasítással egy beütemezett taskot lehet kivenni a végrehajtási sorból, és a resume utasítással ütemezhetõ be újra. Egy aktív task a számára kiosztott idõszelet hátralévõ részérõl a reschedule utasítással mondhat le.

Egy task végrehajtása befejezõdik, ha az utolsóként végrehajtott utasítás a törzs utolsó utasítása vagy egy terminate utasítás volt.

A priority of T kifejezéssel a T azonosítójú task prioritására, míg a timeslice of T kifejezéssel az idõszeletére hivatkozhatunk.

Egy handleren belül a megszakítást kérõ task azonosítójára a caller alapszóval, a típusára a name of caller kifejezéssel hivatkozhatunk.

A következõ példa az ütemezést vezérlõ utasításokat és azok használatát mutatja be:

# schedcon.int
task SchedulingControl in "schedcon.syn"
from......ChildTask
priority..3
timeslice 2 # 20 ms (2 real-time units * 10 ms/real-time unit)


#schedcon.syn
handler IdentifyTheCallerTask
put "Interrupted by
task # ", caller, "named : ", name of caller

entry
var myChild, myPriority:byte
var myTimeslice:word

# creation of a child named ChildTask
myChild := create ChildTask

# print the child taskid in three different ways
put child, id of ChildTask, myChild

# start the execution of myChild
resume child

# print my task id and my parent task id
put self, parent

# save my priority and my time slice
myPriority := priority of self

myTimeslice := timeslice of self

# raise my priority
priority of self := myPriority + 1

# suspend my child, give him my old priority, and start him again
suspend child
priority of child := myPriority
resume child

# raise my time slice by 10 real-time units
timeslice of self := myTimeslice + 10

# give up the processor
reschedule

# when get back here, kill my child, and suicide
terminate child, self

Paraméterátadás a taskoknak

A Synapse lehetõséget ad arra, hogy egy tasknak az elindításakor paramétereket adjunk át. Az alábbi példa ezt mutatja be:

# baby.inc
task Baby(babble:byte[]) in "baby.syn"


# baby.syn
entry
loop
put babble


# suuser.inc
task StartUpUserTasks in "suuser.syn"
from Baby


# suuser.syn
entry
start Baby("Do"), Baby("Ga")
# StartUpUserTask is terminated at this point

Szinkronizáció és a taskok közötti kommunikáció

A Synapse által támogatott konkurens programozási modellben megszakítás útján átadott üzenetekkel kommunikálhatnak a taskok. Egy üzenetet szoftver megszakítással lehet eljuttatni a kívánt task egy handlerének. A szoftver megszakítás egy interrupt utasítás hatására jön létre. Az utasításban egy handler hivatkozás szerepel és lehetnek paraméterek is (csak szoftver megszakítás esetén szerepelhet paraméter). A hívó task a megszakítás létrejöttekor rögtön folytatódik a következõ utasítás végrehajtásával. A megszakítás akkor jöhet létre, amikor a fogadó task egy olyan enable wait utasításhoz ért, amelynek paramétere a kívánt handler azonosítóneve. A hívott taskban végrehajtásra kerül a megfelelõ handler törzse, majd a várakozó utasítást követõ utasításra kerül a vezérlés.

Ez a módszer több szempontból is rugalmas. Egyrészt lehetõvé teszi a szinkron és az aszinkron üzenetátadást. Másrészt az adatáramlás lehet egy- és kétirányú is. Kommunikáción kívül szinkronizációra is alkalmas, ilyenkor nincs adatáramlás egyik irányban sem.


aszinkron kommunikáció

Ez a megszakítási mechanizmus valós idejû rendszerek esetén természetes. A Synapse a taskok közötti aszinkron kommunikációt, mint általános kommunikációs konstrukciót támogatja.

A következõ programban a Receiver task a Sender tasktól egy üzenetet vár:

# sender.inc
task Sender in "sender.syn"
from Receiver import Sync


# sender.syn
entry

# interrupt and continue ...
interrupt Receiver.Sync
...


# receiver.inc
task Receiver in "receiver.syn"
export Sync


# receiver.syn
handler Sync

...

entry
enable wait Sync


szinkron kommunikáció

A taskok közötti szinkron kommunikáció egy randevút igényel azon két task között, amelyek között az egy vagy két irányú adatáramlás létrejön. A küldõ a megszakítási kérelem elküldése után blokkolt állapotba kerül, és mindaddig abban marad, amíg a megszakítást fogadó task egy másik megszakítást nem küld vissza. Ezután mindkét task végrehajtása folytatódhat.

A következõ ábrán a karikával megjelölt nyíl irányában adatátadás történik:

A következõ programban a Sender egy megszakítási kérelmet küld a Receivernek, majd ezután a Sender addig várakozik, amíg nem érkezik egy másik megszakítási kérelem a Receivertõl.


# sender.inc
task Sender in "sender.syn"
from Receiver import Sync
export Reply


# sender.syn
handler Reply
...

entry
# interrupt and wait on Reply

interrupt Receiver.Sync(data)
enable wait Reply


# receiver.inc
task Receiver in "receiver.syn"
from Sender import Reply
export Sync


# receiver.syn
handler Sync
interrupt caller.Reply

entry
# wait on Sync
enable wait Sync
...

Kölcsönös kizárás

A Synapse a handlereken keresztül garantálja a kölcsönös kizárást a task egy globális változójának elérésekor.

A következõ példa a kölcsönös kizárás megvalósítását mutatja be a handlerek segítségével. Az Observer task egy eseményre várakozik, és minden alkalommal megnöveli az eventCount értékét az Update taskban mihelyt észlel egyet. A Reporter task várakozik egy rövid ideig, majd kiírja és törli az eventCount értékét az Update taskban. Az Update task elõször inicializálja a számlálót a nulla értékkel, majd igazságos hozzáférést biztosít az elõzõ két task számára cserélgetve a megszakítási prioritásukat:


# suuser.inc
task StartUpUserTasks in "suuser.syn"
from Update
from Observer
from ReporterP


# suuser.syn
entry
start Update, Observer, Reporter


# update.inc
task Update in "update.syn"
export Report, Observe


# update.syn
var eventCount:word

handler Report
put eventCount
eventCount := 0

handler Observe
eventCount := eventCount + 1

entry
eventCount := 0
loop
# give a fair access by rotating interrupt priorities
enable wait Observe, Report
enable wait Report, Observe


# observer.inc
task Observer in "observer.syn"
from Update import Observe


# observer.syn
entry
loop
# wait for an event ...
interrupt Update.Observe


# reporter.inc
task Reporter in "reporte.syn"
from Update import Report


# reporter.syn
entry
loop
# wait for a while ...
interrupt Update.Report