Platformă software pentru proiectarea aplicațiilor în timp real Absolvent Sandu Adrian-Daniel Coordonator Prof. dr. ing. Monica Drăgoicea București,… [628060]
Universitatea Politehnica București
Facultatea de Automatică si Calculatoare
Departamentul de Automatică și Ingineria Sistemelor
LUCRARE DE LICENȚĂ
Platformă software pentru proiectarea
aplicațiilor în timp real
Absolvent: [anonimizat], 2018
Cuprins
Glosar iv
Listă de figuri iv
Listă de tabele v
Listă de algoritmi vi
1 Jamaica VM 1
1.1 Programare în timp real cu Real-Time Specification for Java (RTSJ) . . . . . . . 1
1.1.1 Programarea firelor de execuție . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Gestionarea memoriei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1 Standard Heap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.2 Immortal Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3 Scoped Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Sincronizarea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3.1 Priority Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.2 Priority Ceiling Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 Evenimente asincrone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.5 Garbage Collection în timp real . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2 Laboratorul 1 – Introducere în Real Time Java 8
2.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2 Mediul de dezvoltare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.1 JamaicaVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.2 Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Instalare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Configurare și utilizare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3 Introducere în Java Real Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.4 Fire de execuție în timp real . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.5 RTSJ Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.6 RTSJ Citire și Afișare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.7 RTSJ Tablou multi-dimensional . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3 Laboratorul 2 – Fire de execuție în timp real 21
3.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2 Clasa RealtimeThread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Constructori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Metode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.3 Crearea unui fir de execuție în timp real . . . . . . . . . . . . . . . . . . . . . . . 25
4 Laboratorul 3 – Planificare,Sincronizare,Fire de execuție periodice 27
4.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.2 Planificare/Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3 Sincronizare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Priorități . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
ii
Cuprins
4.4 Fire de execuție periodice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Hello World – fire de execuție periodice . . . . . . . . . . . . . . . . . . . 32
5 Laboratorul 4 – High-Resolution Time 34
5.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.2 Clasa Clock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Metode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.3 Clasa High-Resolution Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Anexe 37
Bibliografie 37
iii
Glosar
APIApplication Programming Interface. 3
JVM Java Virtual Machine. v,1,27
monitor mecanism ce permite execuția la un moment dat doar a unui singur fir de execuție
pentru a nu bloca fluxul aplicației. 4,5,28
RTSJ Real-Time Specification for Java. ii,1,3,4,5,7,21,22,27,29,34
thread cea mai mică unitate de procesare ce poate fi programată spre execuție de către sistemul
de operare. 2,4,5,6,21,22,23,24,25,26,28,30,31,32
VMVirtual Machine. 3
iv
Listă de figuri
1.1 Thread-urile Java în Java Virtual Machine (JVM)-ul clasic sunt întrerupte de
thread-ul garbage collector-ului. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Thread-urile în timp real pot întrerupe activitatea garbage collector-ului. . . . . 2
1.3 Exemplu de inversare a priorității. . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 Priority Inheritance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.5 Priority Ceiling Protocol. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1 Diagramă JDK-JRE-JVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 Rulare aicasLicenseProvider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3 Interfață grafică Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4 Creare proiect nou în Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5 Setarea JRE-ului pentru proiect . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.6 Finalizare creare proiect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.7 Adăugare clasă proiect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.8 Setări clasă proiect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.9 Adăugare pachet real time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.10 Implementare program Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.11 Debug și Run în Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.12 Licenta Aicas Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.13 Output program Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.1 Priority Inheritance Protocol. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.2 Priority Ceiling Emulation Protocol. . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.3 HW – fire de execuție periodice. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
v
Listă de tabele
vi
Listă de algoritmi
vii
1 Jamaica VM
1.1 Programare în timp real cu RTSJ
Obiectivul specificației în timp real pentru Java( RTSJ) este extinderea limbajului și a biblio-
tecilor standard din Java în vederea realizării unui suport pentru firele de execuție( thread -uri)
în timp real. Execuția acestor thread-uri este supusă anumitor constrângeri de timp. Cu toate
acestea, specificația este compatibilă cu diferite medii de Java și, în același timp, cu aplicațiile
Java ce nu fac obiectivul unei aplicații în timp real.
Cele mai importante îmbunătățiri ale RTSJ vizează următoarele domenii:
•Programarea firelor de execuție. ( thread scheduling )
•Gestionarea memoriei. ( memory management )
•Sincronizarea. ( synchronization )
•Evenimente asincrone. ( asynchronous events )
•Fluxul de control asincron. ( asynchronous flow of control )
•Finalitatea firelor de execuție. ( thread termination )
•Accesul la memoria fizică. ( physical memory access )
Cu aceste optimizări aduse, specificația în timp real pentru Java acoperă și zonele care nu
sunt direct legate de aplicațiile în timp real. Cu toate acestea, aceste domenii prezintă o mare
importanță în cadrul aplicațiilor încorporate în timp real( embedded realtime applications ). Aici
putem menționa accesul direct la memoria fizică sau mecanismele asincrone.
1.1.1 Programarea firelor de execuție
Pentru a permite dezvoltarea unei aplicații în timp real într-un mediu în care garbage collector –
ul oprește execuția thread-urilor aplicației într-un mod imprevizibil, au fost definite clase noi
de thread-uri: RealtimeThread șiNoHeapRealtimeThread . Aceste tipuri de thread-uri nu sunt
afectate sau sunt mai puțin afectate de activitatea garbage collector -ului. De asemenea, sunt
adăugate cel puțin 28 de nivele noi de prioritate în cadrul acestor fire de execuție, cu priorități
ridicate față de cele ale garbage collector -ului.
În figurile de mai jos putem vedea o comparație între firele de execuție în timp real și cele
normale:
1
Capitolul 1. Jamaica VM
Figura 1.1 :Thread-urile Java în JVM-ul clasic sunt întrerupte de thread-ul garbage collector-
ului.
Figura 1.2 :Thread-urile în timp real pot întrerupe activitatea garbage collector-ului.
Firele de execuție din clasa NoHeapRealtimeThread nu pot accesa obiecte alocate în zona
de memorie a garbage collector -ului. Prin urmare, aceste fire de execuție nu sunt influențate de
activitatea sa atâta timp cât prezintă niveluri de prioritate mai mari decât obiectele programate
să acceseze zonele de memorie ale garbage collector -ului. În mediul Java oferit de pachetul
JamaicaVM, restricțiile de acces la memorie prezente în NoHeapRealtimeThread nu sunt necesare
pentru a obține garanții în timp real. În consecință, utilizarea acestor tipuri de thread -uri nu
este nici recomandată, nici necesară.
Pe lângă gama largă a priorităților, clasa RealtimeThread oferă caracteristici necesare în
numeroase aplicații în timp real. Parametrii programați pentru sarcini periodice, termene limită
și constrângeri legate de resurse pot fi transmiși prin intermediul unor fire de execuție în timp
real, și utilizați în implementarea unor algoritmi de planificare având o complexitate mult mai
ridicată. De exemplu, firele de execuție periodice utilizează asemenea parametri.
1.2 Gestionarea memoriei
Pentru ca firele de execuție în timp real să nu fie afectate de activitatea garbage collector -ului,
acestea trebuie să acceseze zone de memorie din afara domeniului de activitate al acestuia. La fel
2
Capitolul 1. Jamaica VM
ca în cazul firelor de execuție, vom avea noi clase de memorie, ImmortalMemory șiScopedMemory
ce furnizează zonele de memorie necesare noilor thread-uri. O consecință importantă a folosirii
acestor zone de memorie este reprezentată de faptul că gestionarea dinamică a memoriei nu este
în întregime sub controlul thread-urilor.
Pe langă cele două noi zone de memorie, Jamaica Virtual Machine (VM) furnizează și o a
treia opțiune de alocare a memoriei,cea Standard Heap utilizată de garbage collector .
1.2.1 Standard Heap
La fel ca și mașinile virtuale standard, mașinile virtuale în timp real mențin o zonă de memorie
alocată – garbage-collected heap utilizată atât de firele de execuție standard cât și de cele în
timp real. Alocând memorie din această zonă, thread-ul poate fi oprit în orice moment de
cătregarbage collector . Există câteva mecanisme utilizate de garbage collector pentru a pune
în echilibru tranziția, scalabilitatea, determinismul și dimensiunea memoriei. Firele de execuție
NoHeapRealtimeThreads nu pot folosi această zonă de memorie tocmai pentru a fi protejate de
acest echilibru ce furnizează o sursă de imprevizibilitate.
1.2.2 Immortal Memory
Immortal Memory este o zonă din afara ariei de acțiune a garbage collector -ului. Odată ce
un obiect este alocat în această zonă de memorie, memoria utilizată de acest obiect nu va
fi, în principiu, recuperată. Utilizarea primordială a acestei zone este ca activitățile să poată
evita alocarea dinamică prin alocare statică a memoriei de care au nevoie înainte de executarea
propriu-zisă și gestionarea ei.
Gestionarea acestei zone de memorie presupune mai multă atenție decât gestionarea me-
moriei alocate în Standard Heap , deoarece există riscul unui leakîn cadrul aplicației, iar obiectele
alocate anterior și vizate de acest leaknu mai pot fi recuperate în mod normal. Astfel, nu există
nicio modalitate facilă de a readuce memoria în zona de Immortal Memory . Ca o observație,
putem face o analogie cu malloc () șifree () din C/C++.
1.2.3 Scoped Memory
RTSJ dispune de un al treilea mecanism de alocare al memoriei numit Scoped Memory . Acesta
este disponbil doar pentru RealtimeThreads șiNoHeapRealtimeThreads . Zonele de memorie din
cadrul acestui mecanism sunt destinate obiectelor cu o durată de viață cunoscută. Aici putem
menționa obiectele temporare create în timpul procesării unui task. La fel ca Immortal Memory ,
zonaScoped Memory nu este accesată de garbage collector . Diferența dintre cele două constă
în faptul că această zonă de memorie este recuperată la sfârșitul duratei sale de viață, după
finalizarea taskului în cadrul căruia a fost alocată.
Acest mecanism furnizează, în plus, și o formă particulară de administrare a memoriei
-memory budgeting . Aceasta constă în specificarea unei dimensiuni maxime a memoriei ce
poate fi alocată în zona respectivă, atunci când este creată. Dacă se încearcă depășirea acestei
dimensiuni va fi returnată o excepție – OutOfMemoryError . Acest lucru asigură faptul că un
task nu va consuma întreaga memorie și prin urmare, un alt task, cu prioritate mai mare, va
putea dispune de memoria necesară execuției.
Pentru fiecare thread, există întotdeauna o zonă activă de memorie, numită context de
alocare curent ( current allocation context ). Toate obiectele alocate firului de execuție sunt
3
Capitolul 1. Jamaica VM
alocate din această zonă. Acest context se schimbă când se execută blocuri de cod cu o zonă de
memorie specifică. Application Programming Interface (API) -ul zonei de memorie dispune de o
metodăenter care determină ca task-ul specificat să fie executat folosind zona de memorie ca pe
un context de alocare curent. În consecință, chiar dacă codul utilizează biblioteci suplimentare
ce alocă memorie, acesta se poate folosi împreună cu zonele de Scoped Memory , iar obiectele
alocate temporar în cadrul acestui cod se vor pierde în momentul în care contextul de alocare
este finalizat.
1.3 Sincronizarea
Sincronizarea este importantă în cadrul schimbului de date, mai ales atunci când acest schimb
de date are loc între 2 thread -uri ce acționează în timp real. De aceea, preocuparea principală
este ca acest schimb de date între cele 2 fire de execuție, dar de priorități diferite, să nu afecteze
comportamentul sistemului în timp real. Nu se dorește ca task-ul cu prioritate mai mică să îi
blocheze activitatea celui cu prioritate mai ridicată.
În cadrul sistemelor în timp real ce dispun de fire de execuție având diferite nivele de
prioritate, pot apărea și trebuie evitate situații de inversare a priorității. Inversarea priorității
are loc atunci când un thread de prioritate ridicată este blocat prin așteptarea unui monitor ce
se află în componența altui thread, dar de prioritate scăzută. În Figura 1.3se poate observa un
exemplu de inversare a priorității. Astfel, thread -ul A, ce dispune de cea mai ridicată prioritate,
trebuie să aștepte după un alt thread B, de prioritate mai mică. De asemenea, se poate observa
că și thread -ul B este blocat din execuție deoarece așteaptă predarea monitor -ului de către
thread -ul C, cel cu prioritatea cea mai mică dintre cele 3 thread -uri. În cazul nostru thread -ul
B împiedică execuția thread -urilor A și C, A fiind blocat, iar C având prioritate scăzută. În
esență, această abordare reprezintă o eroare de programare. Dacă un fir de execuție înglobează
unmonitor de care are nevoie un alt fir de execuție, cu prioritate mai mare, între cele 2 fire de
execuție nu trebuie să existe un alt treilea fir de execuție cu o prioritate intermediară celorlalte
2 fire de execuție.
Figura 1.3 :Exemplu de inversare a priorității.
Pentru a rezolva această problemă, RTSJ propune două alternative:
•Moștenire prioritară ( priority inheritance )
•Protocol de plafon prioritar ( priority ceiling protocol )
4
Capitolul 1. Jamaica VM
1.3.1 Priority Inheritance
Moștenirea prioritară sau Priority Inheritance este un protocol ce prezintă un grad minim de
înțelegere și utlizare, dar poate provoca interblocări( deadlocks ) în execuția aplicației. Utilizarea
acestui protocol presupune ca atunci când un fir de execuție având nivelul de prioritate cel mai
ridicat așteaptă monitor -ul deținut de firul de execuție cu nivelul de prioritate cel mai redus,
prioritatea celui de-al doilea fir de execuție(prioritatea cea mai mică) este amplificată, ajungând
la nivelul de prioritate al firului de execuție cu cea mai ridicată prioritate. Funcționalitatea
acestui protocol este ilustrată în Figura 1.4.
Figura 1.4 :Priority Inheritance.
1.3.2 Priority Ceiling Protocol
Protocolul de plafon prioritar sau Priority Ceiling Protocol este folosit pe scară largă în cadrul
sistemelor critice de siguranță. Prioritatea fiecărui fir de execuție ce interacționează cu moni-
tor-ul este potențată către nivelul maxim de prioritate al oricărui fir de execuție ce ar putea
interacționa cu monitor -ul (Figura 1.5).
Prin urmare, dacă un thread ce utilizează acest protocol în cadrul unui monitor nu se
blochează, orice thread care încearcă să interacționeze cu acest monitor nu se va bloca. Astfel,
utilizarea Priority Ceiling Protocol ne asigură de faptul că în cadrul sistemului nu va exista
blocaj.
Figura 1.5 :Priority Ceiling Protocol.
5
Capitolul 1. Jamaica VM
1.4 Evenimente asincrone
După cum am menționat la începutul capitolului, RTSJ înglobează noi entități de programare
ale limbajului Java. Astfel, am văzut introducerea unor noi tipuri de fire de execuție, Realtime-
Thread șiNoHeapRealtimeThread ce aduc în plus o semantică mai clară și posibilități suplimen-
tare de planificare față de firele de execuție standard din clasa Thread . Evenimentele( Events )
reprezintă un alt concept asemănător firelor de execuție utilizat pentru calcule tranzitorii. Aces-
tea reprezintă o alternativă la firele de execuție normale, însă pentru a minimiza consumul de
resurse se recomandă utilizarea AsyncEvents -urilor pentru secvențe de cod de dimensiuni reduse.
De asemenea, sunt destul de ușor de utilizat deoarece declanșarea lor poate fi programată cu
ușurință, dar nu pot fi utilizate în cadrul funcției de blocare( blocking ). Pentru îndeplinirea aces-
tei funcții există BoundAsyncEvents ce necesită apelarea proprilor fire de execuție. Au același
grad de dificultate ca și AsyncEvents din punctul de vedere al utilizării, dar presupun un consum
mai mare de resurse în comparație cu firele de execuție normale.
AsyncEventHandlers sunt declanșate de evenimente asincrone. Cele 3 medii de execuție,
RealtimeThreads ,NoHeapRealtimeThreads șiAsyncEventHandlers sunt entități programabile,
având parametrii de execuție și parametrii de stare impuși de programator( scheduler ).
Așa cum am stabilit, clasele AsyncEventHandler șiBoundAsyncEventHandler pot genera
un mediu de execuție alternativ. Codul într-o astfel de clasă este executat ca o reacție la un
eveniment( event). Evenimentele pot fi asociate cu evenimente externe(un astfel de eveniment
extern ar putea fi reprezentat de o întrerupere a procesorului), acestea din urmă fiind cele ce le
declanșează pe celelalte. Din punctul de vedere al parametrilor, cele 2 clase se comportă similar
cuRealtimeThread șiNoHeapRealtimeThread . Planificatorul de priorități( priority scheduler )
programează atât firele de execuție cât și agenții de procesare a evenimentelor( event handlers ) în
funcție de gradul de prioritate. De asemenea, poate exista și o validare a parametrilor de execuție
ce trebuie luată în calcul, în cazul ambelor entități menționate anterior. Acești parametrii de
execuție includ valori precum timpul, perioada de execuție și timpul minim între răspunsuri.
O diferență importantă față de thread -uri o constituie faptul că un AsyncEventHandler
nu este legat doar de un singur thread . Prin urmare, același agent de procesare( handler ) poate
fi apelat din medii diferite corespunzătoare unor thread -uri diferite. Există un set de thread -uri
în timp real alocat pentru execuția unor astfel de agenți de procesare. Pot apărea situații în care
un agent de procesare a evenimentelor( event handler ) poate avea o durată de execuție destul
de lungă sau se poate bloca și astfel generează blocarea unui thread din setul alocat. Aceste
situații fac ca execuția unor alți agenți de procesare a evenimentelor să nu se realizeze în timp
util. Orice agent de procesare a evenimentelor care ar putea determina un scenariu similar cu cel
precizat ar trebui să includă, prin urmare, un fir de execuție din clasa RealtimeThread care este
destinat rulării procesului de execuție al event handler -ului. Această caracteristică este oferită
de clasa BoundAsyncEventHandler . Agenții de procesare furnizați de această clasă nu împart
firul de execuție cu alți agenți și în cazul blocării unui astfel de agent, activitatea celorlalți din
sistem nu este afectată.
Din cauza resurselor suplimentare necesare unui BoundAsyncEventHandler , utilizarea lor
ar trebui să fie limitată doar la blocare sau la evenimente de lungă durată. Partajarea firelor de
execuție utilizate în cadrul AsyncEventHandlers permite folosirea unu mare număr de agenți de
procesare a evenimentelor cu accesare minimă de resurse.
1.5 Garbage Collection în timp real
În distribuția curentă de JamaicaVM, pentru un sistem ce suportă garbage collection în timp
real, nu mai este necesară această separare dintre fire de execuție în timp real și fire de exe-
6
Capitolul 1. Jamaica VM
cuție normale. Firele de execuție sunt astfel declanșate doar în funcție de priorități. Garbage
Collector -ul în timp real își desfășoară activitatea într-un mod predictibil. El se activează în
momentul în care memoria este alocată în cadrul aplicației. Activitatea lui asupra alocării tre-
buie să fie preemptibilă astfel încât mai multe thread -uri, a căror execuție este necesară, să fie
active într-un timp cât mai scurt.
Implementarea unui astfel de garbage collector în timp real conduce la rezolvarea sau
evitarea multor provocări tehnice. Activitatea acestuia trebuie să se efectueze prin incrementări
având structuri restrânse din punct de vedere al codului. Acest lucru este necesar deoarece în
cadrul unei incrementări se colectează doar 32 de octeți de memorie. La fiecare alocare, firul de
execuție alocat consumă memorie prin efectuarea unor astfel de incrementări.
RTSJ-ul oferă o extensie puternică a specificațiilor Java. Această extensie își atinge po-
tențialul maxim doar prin utilizarea garbage collector -ului în timp real ce conduce la depășirea
restricțiilor sale.
(JamaicaVM 8.1 — User Manual: Java Technology for Critical Embedded Systems )
7
2 Laboratorul 1 – Introducere în Real Time
Java
În cadrul acestui laborator vom realiza o introducere în limbajul de programare Java și în
special a pachetului de R TSJ (Real Time Specification for Java) oferit de cei de la aicas prin
intermediul JamaicaVM (Jamaica Virtual Machine).De asemenea,ne vom familiariza cu mediul
de dezvoltare Eclipse și vom învața să integrăm acest mediu cu mașina virtuală de la aicas.
2.1 Introducere
În era INTERNET -ului, Java și-a arătat adevărata valoare prin implementarea unor aplicații
software destinate paginilor web, aplicații care nu depind de arhitectura hardware a clienților sau
de browser-ul web folosit. Un exemplu în acest sens îl reprezintă applet-urile WEB. În ultimii
ani, dezvoltarea sistemului de operare Android și utilizarea lui pe tot mai multe dispozitive
mobile, a făcut ca Javasă fie alături de C++ unul din cele mai utilizate limbaje de programare.
Pentru a programa în limbajul Java avem nevoie de un kit de dezvoltare în JAVA –
JDK(Java Developer Kit) produs de firma ORACLE . Oracle pune gratuit la dispoziția dezvol-
tatorilor de aplicații Java, JDK-uri în funcție de sistemul de operare folosit și de arhitectura
mașinii pe care se dorește a se dezvolta aplicația respectivă.În afară de JDK o să introducem și
conceptul de JVM -Java Virtual Machine(Mașină Virtuală Java).
JVM este inima limbajului de programare Java. Când vom rula programul, JVM este
responsabil pentru transformarea bytecode -ului în cod mașină. JVM este, de asemenea, in-
dependent de platformă și oferă funcții de bază, cum ar fi gestionarea memoriei Java, garbage
collector, etc. Putem aloca, de asemenea, o anumită cantitate de memorie pentru JVM .JVM
este o mașină virtuală, deoarece oferă o interfață care este independentă de sistemul de operare
și hardware-ul.
JRE(Java Runtime Environment este o realizare a JVM care oferă o platformă pentru
a rula programe Java. JRE include Java Virtual Machine, fișierele binare și alte clase. JRE
nu conține instrumente pentru dezvoltare (compilator Java, depanator, etc.). Dacă doriți să
rulați orice program Java, trebuie să instalați JRE. În Figura 2.1putem vedea o imagine de
ansamblu a ceea ce înseamna toate aceste 3 concepte definite mai sus. Pachetul JRE se poate
instala separat dar în general este suficient sa instalăm pachetul SDK(Software Development
Kit) deoarece acesta conține atât JRE cat și JDK.
În cadrul acestui laborator dar și pe parcursul celorlalte laboratoare vom folosi Jamai-
caVM ca implementare Real Time Java pentru JDK.
8
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
Figura 2.1 :Diagramă JDK-JRE-JVM
2.2 Mediul de dezvoltare
2.2.1 JamaicaVM
Limbajul de programare Java este utilizat pe scară largă pentru crearea de sisteme complexe și
fiabile. Dezvoltarea acestor sisteme este posibilă și datorită conceptelor de programare orientată
pe obiect generate de Java. Există însă unele sisteme(embedded sau aplicații „time critical “) în
implementarea cărora nu este suficient să folosim limbajul Java clasic. Pentru astfel de sisteme
avem distribuția de JamaicaVM.
După cum am putut vedea tutorialul de instalare si configurare al mediului de lucru,
pentru a folosi pachetul de real time oferit de cei de la aicas prin intermediul JamaicaVM este
necesară rularea executabilului aicasLicenseProvider . Pentru a realiza acest lucru trebuie doar
să deschidem un terminal și să ne deplasăm in directorul unde este descărcată licența, urmând
să introducem instrucțiunea ./aicasLicenseProvider (vezi Figura 2.2). Este necesar să rulăm
această licență ori de câte ori dezvoltăm programe și avem nevoie de caracteristicile oferite de
JamaicaVM.
9
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
Figura 2.2 :Rulare aicasLicenseProvider
2.2.2 Eclipse
Eclipse este un mediu de dezvoltare open-source destinat cu precădere dezvoltatorilor de aplicații
Java. Oferă totuși un suport bogat și pentru alte limbaje de programare precum C/C++,Python,PHP,
dar ca grad de utilizare rămâne cel mai utilizat IDE( Integrated Development Environment ) în
limbajul de programare Java la nivel mondial.
Instalare
Pentru utilizatorii de Windows instalarea mediului Eclipse se poate face astfel:
•Accesăm următorul link: https://www.eclipse.org/downloads/download.php?file=
/oomph/epp/oxygen/R2/eclipse-inst-win64.exe .
•Rulăm executabilul descărcat la pasul anterior.
Pentru Linux procesul de instalare decurge astfel:
•Se descarcă fișierul cu extensia .tarprin comanda corespunzătoare distribuției de Linux
existente pe platforma de lucru – CentOS în cazul nostru.
•Se deschide un terminal și se introduce comanda: sudo tar xfz eclipse-jee-oxygen-2-linux-gtk-
x86 64:tar:gz C/opt/:
Configurare și utilizare
După ce s-a realizat instalarea cu succes, vom porni în execuție pentru prima dată Eclipse. În
cadrul primei rulări va apărea o fereastră în care trebuie să introducem calea către directorul
în care vom salva proiectele. Se alege calea și se apasă pe Launch . Se poate bifa și opțiunea
Use this as the default and do not ask again pentru a nu mai apărea această fereastră la fiecare
10
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
rulare. În momentul acesta devine vizibilă interfața grafică, pe care o putem vedea și în figura
Figura 2.3.
Figura 2.3 :Interfață grafică Eclipse
Pentru a ne familiariza cu modul de lucru și funcțiile din Eclipse vom crea un proiect nou.
Acest proiect va coincide și cu primul proiect realizat în Java Real Time.
Astfel, selectăm File->New->Java Project (vezi Figura 2.4) .
Figura 2.4 :Creare proiect nou în Eclipse
În continuare va trebui să îi dăm un nume proiectului și cel mai important aspect, să setăm
versiunea de JRE ce va fi folosită în rularea aplicației -> jamaica-8.1-1 . În cazul în care această
opțiune nu apare în listă, se recomandă verificarea pașilor existenți în tutorialul de instalare și
configurare al librăriei de JamaicaVM. Dacă totul a fost realizat conform tutorialului, selectați
11
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
această opțiune urmată de Next. Se poate vedea și directorul unde va fi salvat proiectul, fiind
de fapt cel setat la pornirea IDE-ului (Figura 2.5).
Figura 2.5 :Setarea JRE-ului pentru proiect
La pasul 2 trebuie doar să selectăm Finish pentru a crea astfel proiectul. De mențio-
nat faptul că la acest pas putem vedea sursele proiectului și ne mai putem asigura de setarea
librăriilor necesare elaborării programului (Figura 2.6).
Figura 2.6 :Finalizare creare proiect
Următorul pas constă în adăugarea unei clase proiectului, necesară pentru a putea rula
aplicația. Ne amintim că un program în Java conține în structura lui o clasă de bază ce va
fi prima executată. Pentru acest lucru ne ducem în cadrul proiectului nou creat și selectăm
src->New->Class (Figura 2.7).
12
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
Figura 2.7 :Adăugare clasă proiect
Vom avea o fereastră în care introducem numele clasei pe care ne dorim să o creăm și
selectăm Finish . Totul este acum creat și putem începe să scriem cod Java. De menționat că la
acest pas se mai pot stabili setări în ceea ce privește clasa creată (Figura 2.8).
Figura 2.8 :Setări clasă proiect
Avem astfel următorul cod sursă generat:
1p a c k a g e p r i m u l _ p r o i e c t _ j a v a ;
p u b l i c c l a s s T e s t {
3 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
// T O D O Auto g e n e r a t e d method s t u b
5 }
}
13
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
Pentru a ne familiariza cu mediul Eclipse o să realizăm un prim program. Acest program
va coincide cu primul program scris utllizând pachetul Java Real Time. Vom încerca să afișăm un
mesaj. Pentru acest lucru vom crea un thread din clasa RealtimeThread . Mai multe informații
despre această clasă vom vedea în secțiunile următoare. Acum ne concentrăm pe scrierea și
modul de execuție al unui proiect în Eclipse.
Primul pas pe care trebuie să îl facem este să importăm pachetul de real time. Acest lucru
se realizează inserând sintaxa import javax.realtime.* la începutul programului(Figura 2.9).
Figura 2.9 :Adăugare pachet real time
În continuare vom crea un obiect de tipul RealtimeThread pe care îl vom apela utilizând
metodastart. Ca observație putem vedea ca Eclipse-ul are funcție de autocomplete, sugerând
la tastarea primelor litere posibilele variante de sintaxă ce pot fi utilizate în acest context. De
asemenea la selectarea unei sintaxe apare și o scurtă descriere a funcționalității ce vine în ajutorul
utilizatorului (Figura 2.10).
După ce am reușit să scriem codul va trebui să rulăm programul. Pentru acest lucru avem
două moduri: Debug șiRun(Figura 2.11). Modul Debug (cel din stânga) te ajută să vizualizezi
atât codul sursă cât și variabilele în timpul execuției programului. Totuși este recomandat să
fie folosit împreună cu Breakpoints pentru a ne folosi cu adevărat de funcțiile Debuggerului .
Altfel,acesta se comportă ca un simplu Run(dreapta). Un Breakpoint specifică unde se va opri
execuția programului și este utilă pentru a vedea conținutul variabilelor la momentul respectiv
sau chiar pentru a-l modifica.
În cazul nostru,pentru execuția programului vom selecta Run. În momentul primei execuții
va apărea o fereastră în care sunt afișate detalii legate de licența de la aicas(Figura 2.12). Dacă
executabilul este rulat în linia de comandă , putem selecta Okși programul va rula. În Figura 2.13
putem vedea rezultatul execuției programului.
14
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
Figura 2.10 :Implementare program Eclipse
Figura 2.11 :Debug și Run în Eclipse
.
15
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
Figura 2.12 :Licenta Aicas Eclipse
Figura 2.13 :Output program Test
2.3 Introducere în Java Real Time
O specificație în timp real pentru Java este o idee destul de remarcabilă. Programele Java
care rulează pe un JVM sunt, de regulă, mult mai lente decât programele similare scrise în
C și compilate către procesorul țintă. Chiar mai rău pentru timpul real, garbage collection -ul
oprește totul din când în când. Acestea nu sunt caracteristicile unei platforme bune în timp
real. Promisiunea platformei Java în timp real este că Java specifică o platformă completă.
Platforma Java include aspecte ale sistemului dintr-o bibliotecă de clasă robustă și specificație
16
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
lingvistică până la setul de instrucțiuni al procesorului virtual și multe detalii ale runtime-ului
multitasking.
Specificația de Real Time Java îmbunătățește specificația standard de Java prin 6 aspecte:
•Real Time Threads – aceste thread-uri conțin atribute de programare mult mai bine definite
decât thread-urile obișnuite din Java .
•Utilitare și mecanisme care ajută programatorii să scrie cod în Java fără accesarea garbage
collection -ului .
•O clasă ce poate gestiona evenimente asincrone și un mecanism ce asociază aceste eveni-
mente cu ceea ce se întamplă în afara JVM-ului .
•Mecanism numit asynchronous transfer of control ce permite ca un thread să redirecționeze
fluxul de control către un alt thread; în esență acest lucru reprezintă un mod mai controlat
prin care un thread returnează o excepție într-un alt thread .
•Sistem prin care programatorul controlează unde pot fi alocate obiectele în memorie .
•Mecanism ce îi permite programatorului să acceseze anumite adrese de memorie .
Un aspect destul de interesant este faptul că programele obișnuite Java pot rula pe o
implementare a specificației în timp real. Pot chiar să ruleze în timp ce JVM-ul execută codul
în timp real. Mai mult, codul ce nu se execută în timp real nu va interfera cu codul în timp real
decât dacă accesează aceleași resurse.(Dibble )
2.4 Fire de execuție în timp real
Un fir de execuție în timp real( RealTimeThread ) este o instanță a javax.realtime.RealtimeThread .
Specificația de Real Time Java furnizează un interval de cel puțin 28 nivele de prioritate pentru
aceste fire de execuție. Aceste priorități sunt denumite priorități în timp real.
Valoarea de pornire a domeniului de prioritate RealTime nu este mandatată de specificație,
cu excepția faptului că trebuie să fie numeric mai mare decât 10 – valoarea cea mai înaltă de
prioritate dată unui thread obișnuit în Java. Pentru a determina astfel gama de valori de
prioritate este necesar să utilizăm două noi metode, getPriorityMin () șigetPriorityMax () din
clasaPriorityScheduler .
Fiind un laborator introductiv nu ne vom concentra însă pe priorități și vom încerca să
instanțiem un fir de execuție într-un mod cât mai simplu. Vom realiza trei exemple pentru a
învăța modul de lucru cu aceste fire de execuție și pentru a readuce la cunoștință noțiuni de
bază din Java.
2.5 RTSJ Hello World
După cum am putut observa și în exemplul creat anterior implementarea unui proiect trebuie
să includă pachetul javax.realtime .
În cadrul metodei main vom instanția un fir de execuție, iar ca funcționalitate de dorim
să afișeze un simplu mesaj. Codul programului este următorul:
17
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
p a c k a g e hw_fe_rtj ;
2i m p o r t j a v a x . r e a l t i m e . ∗ ;
4 p u b l i c c l a s s HelloRT {
6 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
// I n i t i a l i z a r e a u n u i nou f i r de e x e c u t i e i n timp r e a l
8 R e a l t i m e T h r e a d r t = new R e a l t i m e T h r e a d ( ) {
// Adaugare f u n c t i o n a l i t a t e
10 p u b l i c v o i d run ( ) {
System . o u t . p r i n t l n ( ”H e l l o R e a l Time World ! ! ! ”) ;
12
}
14 } ;
// P o r n i r e f i r de e x e c u t i e i n timp r e a l
16 i f ( ! r t . g e t S c h e d u l e r ( ) . i s F e a s i b l e ( ) )
System . o u t . p r i n t l n ( ”P r i n t i n g h e l l o i s n o t f e a s i b l e ”) ;
18 e l s e
r t . s t a r t ( ) ;
20 }
22 }
În acest program folosim 2 metode: run () șistart () . Metoda starteste cea care pornește
firul de execuție. În esență această metodă apelează metoda run () și se execută codul din
interiorul celei de-a doua metode. Aceste două metode se găsesc și în clasa Thread din Java.
Se mai poate observa utilizarea a încă două metode:
•getScheduler () – returnează planificatorul corespunzător firului de execuție .
•isFeasible () – verifică dacă setul de obiecte din interiorul firului de execuție este fezabil și
returnează truesaufalse.
2.6 RTSJ Citire și Afișare
p a c k a g e c i t i r e _ s c r i e r e ;
2i m p o r t j a v a x . r e a l t i m e . ∗ ;
i m p o r t j a v a . u t i l . ∗ ;
4
6 p u b l i c c l a s s C i t i r e R T {
8 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
R e a l t i m e T h r e a d r t = new R e a l t i m e T h r e a d ( ) {
10 p u b l i c v o i d run ( ) {
System . o u t . p r i n t l n ( ”I n s e r t i n t number : ”) ;
12 i n t x =1;
S c a n n e r s c a n n e r = new S c a n n e r ( System . i n ) ;
14 x =s c a n n e r . n e x t I n t ( ) ;
System . o u t . p r i n t l n ( ”The number i s : ”) ;
16 System . o u t . p r i n t l n ( x ) ;
}
18 } ;
i f ( ! r t . g e t S c h e d u l e r ( ) . i s F e a s i b l e ( ) )
20 System . o u t . p r i n t l n ( ”Reading and P r i n t i n g i s n o t f e a s i b l e ”) ;
e l s e
22 r t . s t a r t ( ) ;
24 }
18
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
26 }
În acest exemplu realizăm citirea unui număr întreg introdus. Pentru acest lucru utilizăm
clasaScanner . Pentru a crea un obiect de tip Scanner , la instanțiere trimitem ca parametru un
obiect predefinit System.in ce reprezintă un flux de intrare standard ( standard input stream ).
Pentru a citi valori numerice utilizăm o metodă nextType () , undeTypereprezintă tipul nume-
ric(în cazul nostru Int).
Explicația folosirii celorlalte metode se găsește în exemplul de mai sus. Ca o observație,
putem menționa că toată funcționalitatea descrisă mai sus se realizează în interiorul unui singur
fir de execuție.
2.7 RTSJ T ablou multi-dimensional
Pentru acest exemplu vom utiliza 2 clase: o clasă pentru crearea unui tablou multi-dimensional
(Matrice ) și o altă clasă pentru citirea elementelor tabloului( CitireRT2 ). Practic, vom avea în
interiorul primei clase un fir de execuție în timp real ce va realiza acest proces, iar pentru citirea
fiecărui element din matrice vom instanția un obiect de tipul clasei CitireRT2 și vom apela
metodele corespunzătoare.
p a c k a g e m a t r i c e ;
2i m p o r t j a v a x . r e a l t i m e . ∗ ;
i m p o r t j a v a . u t i l . ∗ ;
4
6 p u b l i c c l a s s M a t r i c e {
8 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
R e a l t i m e T h r e a d r e a l T i m e = new R e a l t i m e T h r e a d ( ) {
10 p u b l i c v o i d run ( ) {
System . o u t . p r i n t l n ( ”I n s e r t i n t n r f o r columns : ”) ;
12 i n t x ;
S c a n n e r s c a n n e r = new S c a n n e r ( System . i n ) ;
14 x = s c a n n e r . n e x t I n t ( ) ;
16 System . o u t . p r i n t l n ( ”I n s e r t i n t n r f o r rows :”) ;
i n t y ;
18 y = s c a n n e r . n e x t I n t ( ) ;
20 i n t [ ] [ ] a = new i n t [ x ] [ y ] ;
22 f o r (i n t i =0; i <x ; i ++)
{
24 f o r (i n t j =0; j <y ; j ++){
C i t i r e R T 2 c i t i r e = new C i t i r e R T 2 ( ) ;
26 a [ i ] [ j ] = c i t i r e . G e t I n t ( ) ;
}
28 }
30 System . o u t . p r i n t l n ( ”The number i s :”) ;
f o r (i n t i =0; i <x ; i ++){
32 f o r (i n t j =0; j <y ; j ++){
System . o u t . p r i n t ( ” ”) ;
34 System . o u t . p r i n t ( a [ i ] [ j ] ) ;
}
36
System . o u t . p r i n t l n ( ) ;
38 }
}
40 } ;
19
Capitolul 2. Laboratorul 1 – Introducere în Real Time Java
42 i f ( ! r e a l T i m e . g e t S c h e d u l e r ( ) . i s F e a s i b l e ( ) )
System . o u t . p r i n t l n ( ”Reading and P r i n t i n g i n t i s n o t f e a s i b l e ”) ;
44 e l s e
r e a l T i m e . s t a r t ( ) ;
46
48 }
50 }
p a c k a g e m a t r i c e ;
2i m p o r t j a v a x . r e a l t i m e . ∗ ;
i m p o r t j a v a . u t i l . ∗ ;
4
p u b l i c c l a s s C i t i r e R T 2 {
6
i n t x ;
8
p r i v a t e v o i d R e a d I n t ( ) {
10 System . o u t . p r i n t l n ( ”I n s e r t i n t number : ”) ;
S c a n n e r s c a n n e r = new S c a n n e r ( System . i n ) ;
12 x = s c a n n e r . n e x t I n t ( ) ;
}
14
p u b l i c i n t G e t I n t ( ) {
16 Re a d I n t ( ) ;
r e t u r n x ;
18 }
}
În implementare alegem ca după instanțierea unui obiect de tipul clasei CitireRT2 să
apelăm metoda GetInt () ce conține apelul către metoda de citire(vezi exemplul anterior) și
returnează valoarea elementului citit. Din acest motiv alegem ca metoda ReadInt () să fie
private deoarece ne dorim să poată fii apelată doar din interiorul clasei.
20
3 Laboratorul 2 – Fire de execuție în timp real
3.1 Introducere
În laboratorul precedent am văzut ce poate aduce în plus această specificație în timp real pentru
Java(RTSJ), cum se creează un proiect nou în Eclipse și pe lângă aceste lucruri, câteva exemple
de programe scrise și rulate utilizând pachetul javax.realtime . În cadrul acestui laborator vom
studia ceea ce presupune un fir de execuție în timp real,comparația cu un fir de execuție normal
din Java, cum se declară, funcționalități, precum și diferite cazuri sau exemple de utilizare.
Realizarea fluxului unei aplicații în timp real pentru limbajul Java se bazează pe firele de
execuție în timp real( realtime threads ) șiasynchronous event handlers (asemănatoare firelor de
execuție în timp real). Clasa RealtimeThread extinde java.lang.Thread pentru a permite
folosirea unui astfel de thread ori de câte ori este nevoie în program. Așa cum am menționat
și în laboratorul introductiv, există câteva caracteristici ale RTSJ ce sunt disponibile doar prin
intermediul firelor de execuție în timp real:
•Extinderea priorităților – firele de execuție în timp real au o gamă mai largă a priorităților.
•Memorie scoped .
•Serviciu pentru excepții asincrone de întrerupere – asynchronously interrupted exceptions .
•Planificare/Programare periodică – Periodic scheduling .
•Orice planificare fără prioritate furnizată de platformă.
3.2 Clasa RealtimeThread
Clasa RealtimeThread extinde clasa Thread și oferă acces la funcționalități în timp real,
precum transferul asincron de control, memoria non-heap și servicii avansate de planificare.
Ca strucură mai generală, moștenirea se realizează astfel:
• javax.realtime.RealtimeThread <- java.lang.Thread <- java.lang.Object
De asemenea, în ceea ce privește interfețele implementate, avem două astfel de interfețe:
• java.lang.Runnable
• java.lang.Schedulable
Clasa RealtimeThread are și osubclasă ,NoHeapRealtimeThread .
În continuare vom discuta despre structura acestei clase, constructori, metode și particu-
larități.
21
Capitolul 3. Laboratorul 2 – Fire de execuție în timp real
Constructori
Cel mai elaborat constructor al unui fir de execuție în timp real are în componență 6 parametri:
1 p u b l i c R e a l t i m e T h r e a d ( S c h e d u l i n g P a r a m e t e r s s c h e d u l i n g ,
R e l e a s e P a r a m e t e r s r e l e a s e ,
3 MemoryParameters memory ,
MemoryArea a r e a ,
5 P r o c e s s i n g G r o u p P a r a m e t e r s group ,
j a v a . l a n g . Runnable l o g i c )
În cadrul acestui constructor, parametrii declarați reprezintă:
• SchedulingParameters – acest parametru face referință la un obiect care specifică prio-
ritatea noului proces.
• ReleaseParameters – acest parametru este luat în calcul doar în cazul firelor de execuție
periodice(atunci când vorbim despre planificare) , altfel este null.
• MemoryParameters – stabilește limite legate de utilizarea planificatorului de memorie
de către firul de execuție.
• MemoryArea – indică zona de memorie de unde firul de execuție își alocă resurse; implicit,
acesta își alocă memorie din zona heap, dar așa cum am văzut, firele de execuție în timp
real pot aloca resurse din încă două zone noi, immortal șiscoped .
• ProcessingGroupParameters – grupurile de procesare ( processing groups ) au rolul de
a menține sub control activitățile aperiodice; rezultatul utilizării lor constă în limitarea
consumului de resurse al activităților dintr-un grup de thread -uri, pentru a nu depăși în
orice moment de timp cantitatea de resurse alocate grupului.
• Logic – referință către instanța unei clase ce implementează interfața Runnable .
Există și alte forme de implementarea a acestui constructor, fără specificarea tuturor
parametrilor.
Crearea unui fir de execuție în timp real având valori implicite pentru toți parametrii:
1 p u b l i c R e a l t i m e T h r e a d ( )
Constructorul este echivalent cu RealtimeThread(null, null, null, null, null, null) .
Crearea unui fir de execuție în timp real având specificat parametrul de SchedulingPara-
meters și valori implicite pentru restul parametrilor:
1 p u b l i c R e a l t i m e T h r e a d ( S c h e d u l i n g P a r a m e t e r s s c h e d u l i n g )
Constructorul este echivalent cu RealtimeThread(scheduling, null, null, null, null,
null).
Crearea unui fir de execuție în timp real având specificați parametrii SchedulingParameters
șiReleaseParameters , iar pentru ceilalți parametrii valori implicite:
1 p u b l i c R e a l t i m e T h r e a d ( S c h e d u l i n g P a r a m e t e r s s c h e d u l i n g ,
R e l e a s e P a r a m e t e r s r e l e a s e )
22
Capitolul 3. Laboratorul 2 – Fire de execuție în timp real
Constructorul este echivalent cu RealtimeThread(scheduling, release, null, null,
null, null) .
Analizând utilizarea constructorului al doilea(cel cu toți parametrii impliciți), putem spune
că acesta crează și inițiază un obiect de tipul RealtimeThread care este suficient în majoritatea
cazurilor, mai puțin atunci întâlnim un nonpriority scheduler activ(vom discuta despre acesta
în laboratoarele următoare). Totuși, dacă stăm să ne gândim, acest obiect RealtimeThread
moștenește un thread normal, deci, prin urmare, nu poate moșteni atribute specifice RTSJ de
la clasa părinte. Un aspect foarte interesant al acestui caz, în care un fir de execuție în timp
real moștenește un fir de execuție normal, este reprezentat de o valoare implicită a nivelului
de prioritate, numită NORM PRIORITY . Această valoare este echivalentul unei treimi din
lungimea intervalului de priorități corespunzător firelor de execuție în timp real și este folosită
doar pentru acest caz.
Dacă thread -ul moștenește un thread în timp real, acesta va utiliza o copie a parametrilor
planificați( scheduling parameters ), corespunzători thread -ului părinte. În particular, moștenește
prioritatea părintelui.
În ceea ce privește parametrii impliciți ai unui obiect de tip RealtimeThread (sau orice altă
clasă care implementează interfața Schedulable ), aceștia respectă următoarele reguli:
•Moștenesc aceste valori de la thread -ul părinte.
•Dacăthread -ul părinte nu specifică o valoare implicită pentru unul din parametrii, această
valoare devine responsabilitatea planificatorului( scheduler ) care gestionează obiectul.
Metode
Clasa RealtimeThread moștenește metode de la următoarele clase:
• java.lang.Thread – aici menționăm câteva dintre ele: currentThread(), destroy(),
setPriority(), getId(), getName(), getPriority() .
• java.lang.Object – mai exact 8 metode: clone(), equals(), finalize(), notify(), noti-
fyAll(), getClass(), wait(), hashCode() .
• java.lang.Runnable – metoda run() .
Pe lângă aceste metode moștenite, clasa RealtimeThread implementează și metode noi,
specifice acestei clase. În acest laborator le vom menționa pe cele mai utilizate, dar pentru
mai multe detalii puteți consulta documentația accesând https://docs.oracle.com/javase/
realtime/doc_2.1/release/rtsj-docs/javax/realtime/RealtimeThread.html#RealtimeThread() .
Avem următoarele metode:
• currentRealtimeThread() – returnează o referință pentru instanța actuală a Realti-
meThread .
p u b l i c s t a t i c R e a l t i m e T h r e a d c u r r e n t R e a l t i m e T h r e a d ( )
2
• getCurrentMemoryArea() – returnează o referință la obiectul MemoryArea ce repre-
zintă un context de alocare curent.
1 p u b l i c s t a t i c MemoryArea getCurrentMemoryArea ( )
23
Capitolul 3. Laboratorul 2 – Fire de execuție în timp real
• waitF orNextPeriod() .
1 p u b l i c s t a t i c b o o l e a n w a i t F o r N e x t P e r i o d ( )
Această metodă provoacă o întârziere în firul de execuție curent până la începutul perioadei
următoare. Prima perioadă începe atunci când acest fir este lansat inițial. La fiecare apel,
această metodă va bloca firul de execuție până la începutul perioadei următoare. Excepția
apare în cazul în care firul se află într-o condiție limită( deadline miss condition ). În
acest scenariu, funcționarea waitF orNextPeriod este gestionată de planificatorul acestui
thread .
• getScheduler() – returnează o referință la obiectul de tip Scheduler asociat.
1 p u b l i c S c h e d u l e r g e t S c h e d u l e r ( )
• getSchedulingParameters() – returnează o referință la obiectul curent SchedulingPara-
meters .
1 p u b l i c S c h e d u l i n g P a r a m e t e r s g e t S c h e d u l i n g P a r a m e t e r s ( )
• setMemoryParameters() – configurează parametrii de memorie asociați cu această in-
stanțăSchedulable .
1 p u b l i c v o i d setMemoryParameters ( MemoryParameters memory )
Parametrul memory reprezintă un obiect de tip MemoryParameters ce va fi asociat
referinței thisdupă apelare metodei. Dacă acesta este null, valoarea implicită va fi ges-
tionată de scheduler -ul asociat firului de execuție.
• start() – lansează în execuție un thread nou creat.
1 p u b l i c v o i d s t a r t ( )
Această metodă este folosită o singură dată pe parcursul execuției unui thread . În esență
apelează metoda run() .
• sleep() .
1 p u b l i c s t a t i c v o i d s l e e p ( H i g h R e s o l u t i o n T i m e t i m e )
Metoda sleep() este controlată de un ceas generalizat. Această metodă oferă o precizie
la nivelul nanosecundelor datorită exprimării timpului de tipul HighResolutionTime .
Timpul de sleep este relativ sau absolut.
În cazul unui timp relativ, thread -ul ce apelează metoda trece în starea de blocat pentru
o perioadă de timp specificată prin parametrul time. Parametrul time este măsurat de
clock .
Dacă avem un timp absolut, thread -ul care apelează metoda rămâne în starea de blocat
până când valoarea specificată este atinsă de clock . Atunci când valoarea timpului absolut
este mai mică sau mai mare decât valoarea curentă a clock -ului, apelarea metodei sleep
se realizează imediat.
24
Capitolul 3. Laboratorul 2 – Fire de execuție în timp real
Văzând cele două specificații de timp, putem afirma că parametrul time reprezintă inter-
valul de timp în care thread -ul trebuie să ”doarmă” sau momentul de timp la care trebuie
să se ”trezească”.
• interrupt() – suprascrie metoda interrupt() din clasa java.lang.Thread .
1 p u b l i c v o i d i n t e r r u p t ( )
Ca utilizare, această metodă face tranziția din starea de întrerupere în cea de așteptare.
• release() – determină eliberarea firului de execuție în timp real.
1 p u b l i c v o i d r e l e a s e ( )
• setPriority() – setarea noii priorități(parametrul newPriority ) a firului de execuție.
1 p u b l i c v o i d s e t P r i o r i t y ( i n t n e w P r i o r i t y )
• run() – metoda principală a clasei.
1 p u b l i c v o i d run ( )
Metoda runeste declarată o singură dată în interfața Runnable , fiind implementată
în clasa Thread . În cadrul metodei se declară toate activitățile pe care thread -ul le va
executa.
3.3 Crearea unui fir de execuție în timp real
La fel ca și în cazul firelor de execuție din clasa Thread , există două moduri de a crea un thread
din clasa RealtimeThread :
•Se crează o nouă clasă care moștenește clasa RealtimeThread și suprascrie metoda run()
cu noua logică a thread -ului.
•Se crează o instanță a clasei RealtimeThread utilizând un constructor având specificat
parametrul Logic . Se transmite obiectul de tip Runnable a cărei metodă runimplemen-
tează logica thread -ului.
În exemplul de mai jos putem vedea un exemplu simplu de afișare a unui mesaj utilizând
un fir de execuție din clasa RealtimeThread .
1
i m p o r t j a v a x . r e a l t i m e . ∗ ;
3
p u b l i c c l a s s T e s t {
5 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
R e a l t i m e T h r e a d r t = new R e a l t i m e T h r e a d ( ) {
7 p u b l i c v o i d run ( ) {
System . o u t . p r i n t l n ( ”H e l l o R T w o r l d ”) ;
9 }
} ;
11
r t . s t a r t ( ) ;
13 }
}
25
Capitolul 3. Laboratorul 2 – Fire de execuție în timp real
Pentru crearea firului de execuție folosim în implementare un constructor fără parametrii,
astfel încât firul nou creat va moșteni valorile corespunzătoare de la părinte.
În următorul exemplu alegem să creăm un thread din clasa RealtimeThread prin inter-
mediul unui constructor, fixând valori pentru parametrii. Singurul parametru pe care îl vom
considera nulleste ProcessingGroupParameters deoarece nu avem activități aperiodice.
i m p o r t j a v a x . r e a l t i m e . ∗ ;
2
p u b l i c c l a s s RtThCreation {
4 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
S c h e d u l i n g P a r a m e t e r s s c h e d u l i n g =
6 new P r i o r i t y P a r a m e t e r s ( P r i o r i t y S c h e d u l e r . M I N _ P R I O R I T Y + 2 0 ) ;
R e l e a s e P a r a m e t e r s r e l e a s e =
8 new A p e r i o d i c P a r a m e t e r s ( n u l l , n u l l , n u l l , n u l l ) ;
MemoryParameters memory =
10 new MemoryParameters ( MemoryParameters .N O _ M A X , // Heap
0 ) ; // Immortal memory
12 MemoryArea a r e a = HeapMemory . i n s t a n c e ( ) ;
P r o c e s s i n g G r o u p P a r a m e t e r s g r o u p = n u l l ;
14 Runnable l o g i c = new MyThread ( ) ; // a c e a s t a c l a s a t r e b u i e c r e a t a
16 // C r e a r e a t h r e a d u l u i
R e a l t i m e T h r e a d r t = new R e a l t i m e T h r e a d ( s c h e d u l i n g , r e l e a s e , memory , a r e a ,
group , l o g i c ) ;
18
r t . s t a r t ( ) ;
20 t r y {
r t . j o i n ( ) ;
22 } c a t c h ( E x c e p t i o n e ) {
}
24 }
}
26
4 Laboratorul 3 – Planificare,Sincronizare,Fire
de execuție periodice
4.1 Introducere
În acest laborator vom continua să tratăm caracteristicile și specificațiile clasei Realtime-
Thread , vom discuta despre planificare( Scheduling ), sincronizare și o clasă a firelor de execuție,
cele periodice.
4.2 Planificare/Scheduling
RTSJ poate permite mai multe planificatoare( Schedulers ), dar necesită un planificator preemptiv
de priorități fixat( fixed-priority preemptive scheduler ) având în componență cel puțin 28 de
priorități distincte.
Pe lângă cele 28 de priorități specifice dezvoltării în timp real, sunt menținute și cele 10
priorități având ca scop menținerea compatibilității cu aplicațiile destinate platformelor ce nu
implementează RTSJ.RTSJ nu aduce îmbunătățiri în comportamentul priorităților normale, dar
impune ca scheduler -ul să le trateze ca priorități mai mici decât prioritățile minime destinate
pachetului de timp real.
Scheduler -ul dispune de multe caracteristici preferate de programatorii de timp real:
•Regăsim cel puțin 28 de priorități. Uneori, sistemele în timp real necesită mai mult de
28 de priorități, dar rareori suferă în materie de performanță astfel încât să fie nevoite să
aloce 32 de priorități. Deși RTSJ necesită cel puțin 28, folosește un număr întreg pe 32 de
biți pentru a reprezenta prioritățile. Prin urmare, putem observa că specificația de timp
real ar putea suporta și 4 miliarde de priorități, însă acest număr de priorități nu ar putea
fi suportat de planificator.
•Task-urile având priorități mari vor fi întotdeauna preferate task-urilor cu priorități mici.
•Task-urile cu prioritate ridicată vor preîntâmpina task-urile cu prioritate mai mică. Întâr-
zierea maximă dintre momentul de timp în care un task prioritar devine gata de execuție
și momentul de timp în care acesta preia controlul reprezintă o caracteristică ce ține de
JVM, procesor și sistemul de operare compatibil. Nu depinde de cooperarea cu task-ul
având prioritate mai mică.
•Mecanismele de blocare( Locks) aplicate firelor de execuție în timp real folosesc întotdeauna
mijloace de evitare a inversării prioritare( priority inversion ).
27
Capitolul 4. Laboratorul 3 – Planificare,Sincronizare,Fire de execuție periodice
4.3 Sincronizare
(Bollella și Gosling )
Cum Java este un limbaj ce oferă suport pentru multi-threading, va trebui să apelăm la
sincronizare . Fiecare implementare RTSJ trebuie să asigure și să implementeze protocolul de
moștenire a priorității sau priority inheritance protocol pentru toate obiectele de tip synchro-
nized . În schimb, protocolul de plafon prioritar sau priority ceiling emulation protocol este
menționat de standard, dar nu este necesar. Înainte de a vedea exemple de implementări a
acestor protocoale, trebuie să prezentăm ceea ce presupun aceste protocoale.
Cele 2 protocoale menționate mai sus reprezintă mecanisme de evitare a inversării priori-
tății. Inversarea priorității apare atunci când un fir de execuție de prioritate ridicată este blocat
prin așteptarea unui monitor aflat în cadrul altui fir de execuție, dar de prioritate scăzută. Acest
monitor este o instanță a clasei MonitorControl , clasă ce controlează eligibilitatea execuției
thread -ului curent.
O modalitate de combatere a inversării priorității este utilizarea protocolului de plafon
prioritar( priority ceiling protocol ), care oferă fiecărei resurse partajate un plafon prioritar
predefinit. Atunci când un task accesează o resursă partajată, prioritatea task-ului este mărită
la plafonul prioritar al acelei resurse. Este necesar ca plafonul prioritar să fie mai mare decât cea
mai mare prioritate a tuturor task-urilor care pot accesa resursa, asigurând astfel că un task care
deține o resursă partajată nu va fi preferat de niciun alt task care încearcă să acceseze aceeași
resursă. Când task-ul având prioritatea ridicată eliberează resursa, revine la nivelul prioritar
inițial. Orice sistem de operare care permite prioritizarea sarcinilor dinamice poate fi folosit
pentru implementarea acestui protocol.
O alternativă la protocolul pentru plafonul prioritar este reprezentată de protocolul de
moștenire prioritară( priority inheritance protocol ), o variantă ce folosește caracteristicile
priorității dinamice. Astfel, atunci când un task cu prioritate scăzută accesează o resursă par-
tajată, el continuă să ruleze la nivelul priorității inițiale. Dacă un task cu prioritate ridicată
solicită proprietatea resursei partajate, prioritatea task-ului cu prioritate scăzută este mărită
deasupra priorității task-ului solicitant.Task-ul cu prioritate scăzută execută secțiunea critică
în continuare până la eliberarea resursei. Odată ce resursa este eliberată, prioritatea task-ului
revine la nivelul celei inițiale, permițând task-ului cu prioritate ridicată să utilizeze resursa pe
care tocmai a dobândit-o. (Renwick și Renwick )
În Figura 4.1putem observa modul de funcționare al protocolului de moștenire prioritară.
Figura 4.1 :Priority Inheritance Protocol.
28
Capitolul 4. Laboratorul 3 – Planificare,Sincronizare,Fire de execuție periodice
În acest exemplu, prin protocolul de moștenire prioritară, task-ului A îi va fi asignată
prioritatea task-ului C, începând cu momentul în care task-ul C încearcă să îl blocheze pe X
și terminând cu momentul în care task-ul A îl deblochează pe X. Această creștere a priorității
îi permite task-ului A să execute codul dintre acțiunile de blocare și deblocare, fără așteptarea
execuției task-ului B. Altfel spus, pentru ca task-ul C să aibă acces la elementul de blocare( lock)
deținut de task-ul A(task cu deficit de prioritate), este necesară ridicarea priorității task-ului A
pe toată durata deținerii acelui element de către task-ul cu un nivel de prioritate scăzut.
Protocolul plafonului prioritar face ca prioritatea task-ului ce deține blocarea(task-ul A)
să fie mărită temporar peste cea mai ridicată prioritate a oricărui task ce va încerca vreodată să
acceseze elementul de blocare(task-ul C). În cadrul acestui protocol, un task își setează întot-
deauna propria prioritate când dobândește un element de blocare( lock) și își va menține această
nouă prioritate până în momentul în care va elibera acel element. Acest comportament simplifică
implementarea acestui protocol de evitare a inversării prioritare și facilitează înțelegerea secven-
ței de execuție prin intermediul blocării. Funcționalitatea tocmai descrisă poate fi observată și
în Figura 4.2.
Figura 4.2 :Priority Ceiling Emulation Protocol.
Revenind la sincronizare, se poate afirma că funcționarea unui primitiv sincronizat( primitive
synchronized ) trebuie să verifice faptul că nu există nicio inversiune de prioritate nelimitată. În
plus, implementarea trebuie să includă moștenirea prioritară. De asemenea, moștenirea priori-
tară va reprezenta mecanismul implicit de control al monitorizării.
Dacă în cadrul implementării se furnizează mecanismul de emulare a plafonului prioritar
sau orice alt mecanism de creștere a priorității, RTSJ dispune de interfețe care pot aduce mo-
dificări asupra unor astfel de mecanisme, corespunzătoare firelor de execuție în timp real. Un
astfel de exemplu îl întâlnim în următoarea secvență de cod:
i m p o r t j a v a x . r e a l t i m e . ∗ ;
2
p u b l i c c l a s s ToPcep {
4 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
P r i o r i t y C e i l i n g E m u l a t i o n p c e =
6 new P r i o r i t y C e i l i n g E m u l a t i o n ( 2 5 ) ;
// Change d e f a u l t c o n t r o l f o r a l l s y n c l o c k s
8 M o n i t o r C o n t r o l . s e t M o n i t o r C o n t r o l ( p c e ) ;
}
10 }
29
Capitolul 4. Laboratorul 3 – Planificare,Sincronizare,Fire de execuție periodice
În acest exemplu instanțiem un obiect de tip PriorityCeilingEmulation , trimițând ca
parametru valoarea plafonului pe care vrem să o aibă ca referință mecanismul de emulare a
plafonului prioritar. Pe lângă instanțierea clasică a obiectului, putem utiliza și metoda instance :
1 p u b l i c s t a t i c P r i o r i t y C e i l i n g E m u l a t i o n i n s t a n c e ( i n t c e i l i n g )
Parametrul ceiling reprezintă plafonul de prioritate specificat, iar metoda va returna un
obiect PriorityCeilingEmulation având acel plafon impus. Acest obiect va fi repartizat în
zona de Immortal Memory .
În exemplul următor se realizează modificarea protocolului de creștere a priorității imple-
mentată pentru un obiect:
1p a c k a g e p r o t o c o l _ m a r i r e _ p r i o r i t a t e _ o b i e c t ;
i m p o r t j a v a x . r e a l t i m e . ∗ ;
3
p u b l i c c l a s s pp1 {
5 s t a t i c P r i o r i t y C e i l i n g E m u l a t i o n p c e =
P r i o r i t y C e i l i n g E m u l a t i o n . i n s t a n c e (
7 P r i o r i t y S c h e d u l e r . g e t M a x P r i o r i t y ( n u l l ) 5) ;
p u b l i c s y n c h r o n i z e d i n t f o o ( ) {
9 r e t u r n 1 ;
}
11 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
p c e 1 o b j = new pp1 ( ) ;
13 // S e t PCe p r o t o c o l f o r j u s t one o b j e c t
M o n i t o r C o n t r o l . s e t M o n i t o r C o n t r o l ( o b j , p c e ) ;
15 System . o u t . p r i n t l n ( o b j . f o o ( ) ) ;
17 }
19 }
Observăm utilizarea metodei instance menționată anterior. În plus, de data aceasta
nu mai specificăm numeric prioritatea plafonului, ci doar o fixăm raportându-ne la prioritatea
maximă returnată de planificator.
Fixarea unui plafon global de prioritate poate fi o abordare potrivită pentru o aplicație
care folosește sincronizarea într-un mod facil, dar nu și în cadrul unei aplicații multi-threading.
Într-o astfel de aplicație Java multi-threading, utilizarea unui plafon global va face ca toate firele
de execuție să ruleze la un nivel de prioritate maxim într-un interval de timp destul de lung.
Priorități
Ne propunem să modificăm prioritatea unui fir de execuție. Un fir de execuție își poate modifica
propria prioritate sau poate schimba prioritatea altor fire de execuție. Pentru a realiza această
schimbare de prioritate trebuie să modificăm obiectul de tip PriorityParameters asociat cu
thread -ul. Prin urmare, rezultă 2 moduri prin care putem face acest lucru:
•Modificarea priorității asociate obiectului PriorityParameters .
1p a c k a g e s c h i m b a r e _ p r i o r i t a t e _ f i r _ e x e c _ P r P a r a m ;
3i m p o r t j a v a x . r e a l t i m e . P r i o r i t y P a r a m e t e r s ;
i m p o r t j a v a x . r e a l t i m e . R e a l t i m e T h r e a d ;
5
p u b l i c c l a s s Schimbarep i m p l e m e n t s Runnable {
7 p u b l i c v o i d run ( ) {
R e a l t i m e T h r e a d r t = R e a l t i m e T h r e a d . c u r r e n t R e a l t i m e T h r e a d ( ) ;
30
Capitolul 4. Laboratorul 3 – Planificare,Sincronizare,Fire de execuție periodice
9 i n t P r I n i t i a l a ;
P r i o r i t y P a r a m e t e r s p r i o r i t y ;
11 p r i o r i t y = ( P r i o r i t y P a r a m e t e r s ) r t . g e t S c h e d u l i n g P a r a m e t e r s ( ) ;
P r I n i t i a l a = p r i o r i t y . g e t P r i o r i t y ( ) ;
13 System . o u t . p r i n t l n ( ”P r i o r i t a t e a i n i t i a l a a t h r e a d u l u i = ”+ P r I n i t i a l a ) ;
p r i o r i t y . s e t P r i o r i t y ( P r I n i t i a l a + 5 ) ;
15 System . o u t . p r i n t l n ( ”Noua p r i o r i t a t e a t h r e a d u l u i = ”+ p r i o r i t y . g e t P r i o r i t y
( ) ) ;
}
17
}
•Înlocuirea obiectului PriorityParameters cu altul, având nivelul de prioritate dorit.
p a c k a g e s c h i m b a r e _ p r i o r i t a t e _ f i r _ e x e c _ P r P a r a m ;
2
i m p o r t j a v a x . r e a l t i m e . P r i o r i t y P a r a m e t e r s ;
4i m p o r t j a v a x . r e a l t i m e . R e a l t i m e T h r e a d ;
i m p o r t j a v a x . r e a l t i m e . S c h e d u l i n g P a r a m e t e r s ;
6
p u b l i c c l a s s Schimbarep i m p l e m e n t s Runnable {
8 p u b l i c v o i d run ( ) {
R e a l t i m e T h r e a d r t = R e a l t i m e T h r e a d . c u r r e n t R e a l t i m e T h r e a d ( ) ;
10 i n t P r I n i t i a l a ;
P r i o r i t y P a r a m e t e r s p r i o r i t y ;
12 p r i o r i t y = ( P r i o r i t y P a r a m e t e r s ) r t . g e t S c h e d u l i n g P a r a m e t e r s ( ) ;
P r I n i t i a l a = p r i o r i t y . g e t P r i o r i t y ( ) ;
14 Npp = new P r i o r i t y P a r a m e t e r s ( P r I n i t i a l a + 5 ) ; // Noul o b i e c t de t i p
// P r i o r i t y P a r a m e t e r s
16 r t . s e t S c h e d u l i n g P a r a m e t e r s ( ( S c h e d u l i n g P a r a m e t e r s ) Npp ) ;
System . o u t . p r i n t l n ( ”Noua p r i o r i t a t e a t h r e a d u l u i = ”+ Npp . g e t P r i o r i t y ( ) ) ;
18 }
20 }
Observație: Dacă se alege folosirea aceluiași obiect PriorityParameters în cadrul mai
multor fire de execuție, orice modificare asupra priorității obiectului respectiv duce la modificarea
priorității firelor de execuție care îl includ.
4.4 Fire de execuție periodice
Firele de execuție periodice prezintă o structură standard. Multe din caracteristicile necesare
planificării( scheduling ) unui thread periodic pot fi transmise constructorului prin intermediul
ReleaseParameters sau se pot seta chiar în interiorul firului de execuție.
Modalitatea de planificare cu ajutorul ReleaseParameters se regăsește în exemplul de
mai jos:
p a c k a g e setPdThread ;
2
i m p o r t j a v a x . r e a l t i m e . ∗ ;
4
p u b l i c c l a s s P e r i o d i c T h 1 {
6
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
8 // T O D O Auto g e n e r a t e d method s t u b
S c h e d u l i n g P a r a m e t e r s s c h e d u l i n g =
10 new P r i o r i t y P a r a m e t e r s ( P r i o r i t y S c h e d u l e r . M I N _ P R I O R I T Y + 5 ) ;
R e l e a s e P a r a m e t e r s r e l e a s e =
12 new P e r i o d i c P a r a m e t e r s (
31
Capitolul 4. Laboratorul 3 – Planificare,Sincronizare,Fire de execuție periodice
new R e l a t i v e T i m e ( ) , // P o r n i r e l a a p e l u l s t a r t ( )
14 new R e l a t i v e T i m e ( 1 0 0 0 , 0 ) , // P e r i o a d a = 1 s e c
n u l l , // Cost
16 new R e l a t i v e T i m e ( 5 0 0 , 0 ) , // D e a d l i n e = 1/2 ∗ P e r i o a d a
n u l l , // Fara o v e r r u n h a n d l e r
18 n u l l ) ; // Fara m i s s h a n d l e r
20 R e a l t i m e T h r e a d r t = new R e a l t i m e T h r e a d ( s c h e d u l i n g , r e l e a s e ) ;
r t . s t a r t ( ) ;
22 t r y {
r t . j o i n ( ) ;
24 } c a t c h ( E x c e p t i o n e ) {
}
26 ;
}
28
}
În ReleaseParameters observăm o serie de parametri, pe unii dintre ei setându-i explicit,
iar pe alții lăsându-i cu valoarea de null:
• start – specifică momentul în care firul își începe execuția; poate fi un timp absolut( 10:00
AM July 4,2018 ) sau relativ( 500 ms de la momentul invocării unei metode); în exemplul
nostru presupune chiar imediat.
• period – reprezintă intervalul de timp dintre două iterații ale buclei(în cazul thread -urilor
intervalul de timp dintre start-start, nu start-end).
• cost- constituie timpul de procesare alocat fiecărei lansări în execuție; dacă avem imple-
mentări care pot măsura timpul necesar executării unui obiect planificabil, această valoare
va reprezenta timpul maxim pe care un obiect planificabil îl primește la fiecare execuție.
• deadline – momentul maxim de timp la care obiectul programabil trebuie să își încheie
procesarea.
• overrunHandler – introduce un asynchronous event handler ce acționează în momentul
în care firul de execuție consumă un timp de procesare mai mare decât cost-ul specificat.
• missHandler – introduce un asynchronous event handler care se declanșează atunci când
firul de execuție ratează deadline -ul.
Hello World – fire de execuție periodice
1i m p o r t j a v a x . r e a l t i m e . ∗ ;
3 p u b l i c c l a s s P e r i o d i c H e l l o e x t e n d s R e a l t i m e T h r e a d {
5 P e r i o d i c H e l l o ( P e r i o d i c P a r a m e t e r s p e r i o d i c ) {
s u p e r (n u l l , p e r i o d i c ) ;
7 }
9 p u b l i c v o i d run ( ) {
f o r (i n t i =0; i <10; i ++){
11 System . o u t . p r i n t l n ( ”H e l l o World ! > R e a l Time ”) ;
w a i t F o r N e x t P e r i o d ( ) ;
13 }
}
15
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
17 P e r i o d i c P a r a m e t e r s p e r i o d i c = new P e r i o d i c P a r a m e t e r s ( new R e l a t i v e T i m e ( 1 0 0 0 , 0 ) ) ;
32
Capitolul 4. Laboratorul 3 – Planificare,Sincronizare,Fire de execuție periodice
P e r i o d i c H e l l o r t = new P e r i o d i c H e l l o ( p e r i o d i c ) ;
19 r t . s t a r t ( ) ;
t r y {
21 r t . j o i n ( ) ;
} c a t c h ( I n t e r r u p t e d E x c e p t i o n e ) {
23
}
25
}
27
}
În urma rulării programului se observă afișarea mesajelor(vezi Figura 4.3) la o diferență
de o secundă între ele. Acest lucru se datorează impunerii parametrului periodic de 1 secundă.
Figura 4.3 :HW – fire de execuție periodice.
33
5 Laboratorul 4 – High-Resolution Time
5.1 Introducere
După cum ne așteptam, timpul reprezintă un aspect important în dezvoltarea aplicațiilor în
timp real. RTSJ necesită un concept de timp mult mai puternic și bine definit decât cel oferit
de clasa java.util.Date în Java. Astfel, se introduce o clasă, HighResolutionTime și cele 3
subclase ale acesteia( AbsoluteTime ,RelativeTime ,RationalTime ) ce implementează două
caracteristici esențiale pentru RTSJ :
•reprezentare polimorfică a timpului – posibilitate de utilizare a intervalelor în timp, puncte
fixate în timp și reprezentare a frecvenței.
•reprezentarea timpului la nivel de nanosecunde și a unor intervale de timp având durate
de milioane de ani.
5.2 Clasa Clock
Clasa Clock este o clasă abstractă. Un obiect de tip Clock marchează trecerea timpului.
Momentul de timp curent poate fi obținut prin apelarea sintaxei Clock.getTime () .
Constructor
p u b l i c C l o c k ( )
Metode
• getRealtimeClock() – returnează o instanță singleton a Clock -ului implicit.
1 p u b l i c s t a t i c C l o c k g e t R e a l t i m e C l o c k ( )
• getResolution() – returnează un obiect RelativeTime nou alocat, reprezentând rezolu-
ția luithis; obiectul returnat este asociat cu clock-ul this.
1 p u b l i c a b s t r a c t R e l a t i v e T i m e g e t R e s o l u t i o n ( )
• setResolution() – setează rezoluția lui this; parametrul resolution trebuie să corespundă
unor anumite valori acceptate de clock.
1 p u b l i c a b s t r a c t v o i d s e t R e s o l u t i o n ( R e l a t i v e T i m e r e s o l u t i o n )
34
Capitolul 5. Laboratorul 4 – High-Resolution Time
Exemplul de mai jos utilizează în implementare câteva din metodele amintite mai sus și
are ca obiectiv afișarea preciziei( resolution )clock -ului în timp real.
1p a c k a g e c l o c k E x a m p l e ;
i m p o r t j a v a x . r e a l t i m e . ∗ ;
3
p u b l i c c l a s s ClockExample {
5
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
7
R e l a t i v e T i m e t =
9 C l o c k . g e t R e a l t i m e C l o c k ( ) . g e t R e s o l u t i o n ( ) ;
System . o u t . p r i n t l n (
11 ”Real t i m e c l o c k r e s o l u t i o n = ”+ t . t o S t r i n g ( ) ) ;
13 }
15 }
(Bruno și Bollella )
5.3 Clasa High-Resolution Time
Fiind o clasă abstractă, clasa HighResolutionClass nu poate fi instanțiată, dar oferă o gamă
largă de metode și atribute ce pot fi utilizate în cadrul subclaselor sau a claselor ce o moștenesc.
Mai jos regăsim lista metodelor și a atributelor:
•
35
Anexe
36
Bibliografie
Bollella, Gregory și Gosling, James (). The real-time specification for Java . Computer, vol.
33(6), pags. 47–54.
Bruno, Eric J și Bollella, Greg (). Real-Time Java Programming: With Java RTS . Pearson
Education.
Dibble, Peter (). Real-time Java platform programming . Prentice Hall Professional.
JamaicaVM 8.1 — User Manual: Java Technology for Critical Embedded Systems (). Aicas
GmbH.
Renwick, Kyle și Renwick, Bill (). How to use priority inheritance . Embedded Systems
Programming, pag. 15.
37
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Platformă software pentru proiectarea aplicațiilor în timp real Absolvent Sandu Adrian-Daniel Coordonator Prof. dr. ing. Monica Drăgoicea București,… [628060] (ID: 628060)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
