Oberon activ

Versiunea actuală a paginii nu a fost încă revizuită de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită la 9 ianuarie 2018; verificările necesită 16 modificări .
Oberon activ
Clasa de limba imperativ , modular , orientat pe obiecte , multithreading , structural , tip sigur
Tipul de execuție compilat , interpretat
Aparut in 1997
Autor Brinch Hansen, Jürg Gutknecht , Pieter Muller , Patrik Reali
Extensie de fișier .Mod, mod
Eliberare 2019
Tip sistem static , puternic
Implementări majore Activ Oberon.Net, FOX, PACO, Ronin
Dialectele Zonnon
A fost influențat MATLAB , Modula-2 , Oberon , Object Oberon , Pascal
influențat Active C# [1] , Composita, Go , Zonnon
Site-ul web a2.inf.ethz.ch
Platformă ARM , Celulă , JVM , .NET , x86-32 , x86-64
OS A2 , Darwin , Linux , Solaris , Windows

Active Oberon este  un limbaj de programare de uz general, sigur de tip, modular , orientat pe obiecte  , dezvoltat în 1996-1997 . un grup de prof. Gutknecht la ETH Zurich (ETHZ) cu ​​scopul de a introduce în limbajul Oberon proprietăți pentru exprimarea concurenței prin obiecte active [2] .

Caracteristicile limbii

Numele Active Oberon reflectă conceptul principal al limbajului - conceptul de Active Objects , exprimat în implementarea mecanismelor de multithreading și sincronizare la nivel de limbaj.

Active Oberon extinde limbajul Oberon prin introducerea conceptelor de Obiect și Activitate asociate unui Obiect. O astfel de relație se numește obiect activ și înseamnă capacitatea unei instanțe de obiect de a avea o activitate - propriul fir de execuție [2] .

Limbajul aparține limbajelor de programare modulare sigure de tip, cu tastare statică puternică , permițând turnarea implicită a tipurilor scalare în expresii fără pierderi de date (de exemplu, folosind un număr întreg în care trebuia să fie utilizat un număr în virgulă mobilă).

Modulele oferă nu numai compilare , încapsulare separată , ci și capacitatea de a implementa încărcarea / descărcarea dinamică a modulelor (obiect) compilate, care este utilizată, de exemplu, în sistemul de operare A2 scris în acest limbaj. Într-un fel, o bibliotecă de legături dinamice poate fi considerată un analog al unui modul .

În Active Oberon, ca și în ceilalți succesori ai Modula-2 , la accesarea entităților unui modul conectat (import), este necesară o calificare obligatorie a modulului conectat. De exemplu, dacă modulul A include modulul B și utilizează variabila v a modulului , atunci referința variabilei trebuie să aibă forma Bv . Cu alte cuvinte, importul în Active Oberon nu permite implicit importarea din modulul conectat a tuturor entităților pe care le exportă.

Încapsularea este construită pe conceptul unui modul - toate tipurile declarate într-un modul sunt complet transparente unele pentru altele, iar specificatorii de acces sunt necesari pentru accesul de către clienții externi . Specificatorii de acces vă permit să exportați entități fie cu acces complet (identificatorul este marcat cu un „*” (asterisc)), fie cu acces numai pentru citire (identificatorul este marcat cu un semn „-” (minus)). De exemplu, construcția:

TIP Exemplu1 * = RECORD x * , y - , z : LONGINT ; SFÂRȘIT ;

definește tipul de înregistrare (RECORD) Exemplu1 , exportat în afara modulului și având trei câmpuri de tip „întreg lung”, iar câmpul „ x ” este declarat cu specificatorul de acces „acces complet”, câmpul „ y ” este declarat cu specificatorul „acces numai în citire” și câmpul „ z ” este un câmp ascuns, care nu este accesibil clienților externi.

Limbajul acceptă polimorfismul , supraîncărcarea operatorilor (pentru tipuri structurale), delegații care sunt compatibile atât cu metodele, cât și cu procedurile. Tipurile de obiecte sunt RECORD și tipul de referință OBJECT . Ele pot avea metode și operații. Un tip de OBIECT poate avea un corp și o activitate. Toate metodele sunt virtuale . Nu există moștenire multiplă , în schimb se folosește conceptul de moștenire multiplă a interfețelor ( DEFINIȚIE în termeni lingvistici).

Sintaxă și semantică

Sintaxa limbajului practic nu se schimbă în timpul dezvoltării - dezvoltatorii preferă să rafineze semantica construcțiilor sintactice existente folosind modificatorii semantici introduși , ceea ce face posibilă eliminarea unei cantități semnificative de editări la introducerea de noi funcționalități, simplificarea compilatorului, făcându-i codul este mai accesibil pentru înțelegere și modificare și oferă, de asemenea, ușurință în învățare și utilizare a limbii. Modificatorii sunt încadrați în acolade {} după un nume de variabilă, un tip sau un cuvânt cheie. De exemplu, construcția:

VAR Exemplu2 : PROCEDURA { REALTIME , C } ( VAR mic , mare : LONGINT ): BOOLEAN ;

declară o variabilă procedurală Exemplul2 care indică o procedură în timp real cu convenția de apelare CCALL care ia doi parametri de tip întreg lung și returnează o valoare booleană.

Descrierea obiectului, în general, corespunde descrierii modulului , cu excepția sintaxei antetului și a absenței secțiunii IMPORT. Metodele sunt descrise în întregime în interiorul descrierii obiectului; operațiunile, cu rare excepții, pot fi descrise în afara corpului obiectului. Un obiect poate avea un număr arbitrar de inițializatoare și nu mai mult de un finalizator . Procedura încorporată NEW , care este folosită pentru a crea variabile de tip referință, apelează un inițializator ales de compilator pe baza semnăturii parametrilor. Inițializatorul este marcat cu & în fața numelui metodei. Un finalizator, o metodă fără parametri precedată de semnul ~ , este apelat automat atunci când un obiect este eliminat.

O secvență de instrucțiuni cuprinse între paranteze de instrucțiune BEGIN END se numește bloc de instrucțiuni . Blocul de instrucțiuni poate conține, de asemenea, o listă de modificatori și o secțiune de completare garantată ( FINALY ).

O variabilă, precum și un câmp al unei înregistrări sau al unui obiect, pot fi inițializate cu o expresie constantă atunci când sunt declarate:

TIP Punct = RECORD x := 0 , y := 0 : LONGINT ; SFÂRȘIT ; VAR i := 0 , j := 10 , k := 100 : INTEGER ; Punct : Punct ; (* câmpurile x, y ale înregistrării sunt inițializate la 0 *)

Tipuri de date

Limbajul oferă un set bogat de tipuri încorporate:

  • Tipuri de bază
    • boolean: BOOLEAN ;
    • caracter: CHAR8 , CHAR16 , CHAR32 și alias -ul CHAR pentru tipul de caracter implicit;
    • numere întregi cu semn: SIGNED8 , SIGNED16 , SIGNED32 , SIGNED64 și aliasuri SMALLINT , INTEGER , LONGINT , HUGEINT ;
    • numere întregi fără semn: UNSIGNED8 , UNSIGNED16 , UNSIGNED32 , UNSIGNED64 ;
    • real: REAL , LONGREAL ;
    • complex: COMPLEX , LONGCOMPLEX ;
    • dependent de mașină: DIMENSIUNE , ADRESĂ ;
    • set: SET, SET8, SET16, SET32, SET64 ;
    • enumerari extensibile: ENUM ;
  • structural
    • tablouri: ARRAY  - static, dinamic, deschis, matematic;
    • structuri extensibile: RECORD ;
    • obiect: OBIECTUL ;
  • Special
    • procedural;
    • delegati: variabile procedurale compatibile atat cu procedurile cat si cu metodele;
    • indicatoare tipizate către tipuri structurale;
    • pointeri generici: ANY , OBJECT , ARRAY ;
  • sistem: SYSTEM.BYTE

Multithreading

Pentru Active Oberon, sunt implementate două modele multithreading, bazate pe munca lui Brinch Hansen și Tony Hoare [3] :

Codul sursă scris folosind sintaxa primitivă de sincronizare de blocare a lui Active Oberon poate fi folosit pentru ambele modele de multithreading - compilatorul va genera codul necesar pentru un anumit model. Cu această abordare, nu este nevoie să rescrieți software-ul pentru diferite modele. Doar porțiuni mici de cod sursă necesită adaptare (cum ar fi gestionarea întreruperilor) pentru a suprima generarea automată de comutatoare într-o anumită porțiune a codului mașină. Pentru a face acest lucru, blocul de instrucțiuni este marcat cu modificatorul {UNCOOPERATIVE} .

Obiecte active

Un fir este încapsulat într-un obiect și, fiind parte integrantă a acestuia, este creat în momentul în care obiectul activ este instanțiat . Pentru a indica activitatea unui obiect, corpul acestuia este marcat cu modificatorul ACTIV .

După ce instanța obiectului a fost alocată , inițializatorul (dacă există) este executat, apoi corpul obiectului (dacă există). Dacă obiectul este marcat ca activ, se creează o activitate în care corpul obiectului este executat asincron, în caz contrar execuția se realizează sincron pe firul în care a fost creată instanța.

Activitatea unui obiect se încheie atunci când execuția corpului obiectului este finalizată. În timp ce corpul se execută, obiectul continuă să existe, chiar dacă nu există referințe la el. După aceea, obiectul devine pasiv și poate fi eliminat conform regulilor normale.

Un exemplu de descriere și utilizare a unui obiect activ:

MODUL Exemplu3 ; TIP ActiveObject = OBIECT Stare VAR : SET ; PROCEDURA & Nou ; ÎNCEPE stare := {}; END Nou ; PROCEDURE & Init * ( stare : SET ); ÎNCEPE SINELE . stare := stare ; END Init ; PROCEDURA ~ Finalizez ; ÎNCEPE ... END Finalize ; ÎNCEPE { ACTIV } ... END ActiveObject ; VAR obiect : ActiveObject ; ÎNCEPE NOU ( obiect ); obiect . Init ( { 0 .. 7 , 9 , 12 , 30 .. 31 } ); NOU ( obiect , {} ); END Exemplul3 . Comunicare între procese

Apelurile la metode de partajare a obiectelor active și inactive acționează ca un mecanism de comunicare între obiectele active. Deoarece obiectele active există într-un mediu cu mai multe fire, este prevăzut un mecanism pentru coordonarea accesului concurent la starea lor. Interacțiunea prin mesagerie poate fi realizată folosind cadre software speciale [5] .

Protecție simultană

Un bloc de instrucțiuni marcat cu modificatorul EXCLUSIV se numește regiune exclusivă . Zona exclusivă din Active Oberon corespunde conceptului de zonă critică a lui Hansen [6] . Dacă domeniul exclusiv de aplicare acoperă întregul corp al metodei, atunci se numește metodă exclusivă (metodă exclusivă) și combină conceptul lui Hansen cu procedura monitorului Hoare [7] [8] . Spre deosebire de o procedură de monitorizare, o metodă de obiect nu trebuie să fie exclusivă, caz în care poate observa stări inconsistente ale obiectului. Un domeniu de aplicare exclusiv poate avea cel mult o activitate la un moment dat.

Astfel, modelul de securitate din Active Oberon este un monitor plasat pe un monitor bazat pe instanță . Un modul este considerat un tip de obiect de instanță singleton, iar procedurile sale pot fi, de asemenea, exclusive, protejând modulul ca întreg.

Ideea principală a unui monitor (și a unui obiect activ) este că un anumit invariant  este asociat cu monitorul - o expresie care determină starea internă consecventă a obiectului și dovedește corectitudinea comportamentului său [9] . Inițializatorii și metodele exclusive sunt instrumente furnizate de limbaj pentru menținerea invarianților unui obiect și ascunderea stării sale interne. Inițializatorul unui obiect își stabilește invariantul, iar metodele exclusive îl susțin. Atunci când noţiunea de monitor este combinată cu noţiunea de modul, se formează un mecanism puternic de structurare a sistemelor de operare [10] [11] [12] .

Un exemplu de utilizare a secțiunii exclusive:

(* Procedurile de setare și resetare se exclud reciproc *) TIP MyContainer = OBIECT VAR x , y : LONGINT ; (* Invariant: y = f(x) *) Set PROCEDURĂ ( x : LONGINT ); BEGIN { EXCLUSIV } (* schimbând x și y atomic *) SINELE . x := x ; y := f ( x ) END Set ; PROCEDURA Resetare ; ÎNCEPE ... BEGIN { EXCLUSIV } (* schimbând x și y atomic *) x := x0 ; y := y0 ; SFÂRȘIT ; .... END Resetare ; END MyContainer ; Sincronizare

Spre deosebire de majoritatea implementărilor de monitor care utilizează variabilele condiționate ale lui Hoare [8] pentru sincronizare (pe baza cozilor de evenimente ale lui Brinch Hansen [6] ), sincronizarea activităților este asigurată de operatorul AWAIT , care ia ca argument o expresie logică - o condiție pentru continuarea programului. executarea în corpul unui obiect. Pentru a asigura o sincronizare adecvată, AWAIT trebuie să fie în domeniul exclusiv. Dacă condiția de continuare nu este îndeplinită , AWAIT suspendă activitatea și, dacă este într-un domeniu exclusiv, eliberează zona capturată pe durata suspendării, ceea ce permite altor activități să schimbe starea obiectului și să facă adevărată condiția de continuare. O activitate suspendată va continua să ruleze numai dacă poate reintra în domeniul exclusiv.

Un exemplu de sincronizare în interiorul unui buffer partajat:

TIP Sincronizator = OBIECTUL VAR wake : BOOLEAN PROCEDURA Așteaptă ; ÎNCEPE { EXCLUSIV } AWAIT ( treaz ); treaz := FALS ; SFÂRȘIT Așteaptă ; PROCEDURA WakeUp ; ÎNCEPE { EXCLUSIV } treaz := ADEVĂRAT ; sfârșitul trezirii ; Sincronizator END ;

Gestionarea erorilor și excepțiilor

Active Oberon nu are gestionarea structurată a excepțiilor - acestea sunt gestionate central de mediul de rulare.

Instrucțiunea ASSERT ia drept argument obligatoriu o expresie logică, în cazul încălcării căreia programul este întrerupt și, la fel ca atunci când se execută instrucțiunea stop necondiționat HALT , controlul este transferat către handler-ul centralizat de excepții. Dacă condiția instrucțiunii ASSERT poate fi evaluată în timpul compilării, atunci este generată o eroare de compilare dacă condiția nu este îndeplinită. Instrucțiunile ASSERT și HALT pot avea un parametru opțional, un specificator de excepție, care poate fi analizat de handler.

După ce excepția a fost gestionată, controlul este transferat la următoarea secțiune de finalizare garantată ÎN FINAL din stiva de apeluri , dacă aceasta există. Apoi, dacă corpul obiectului activ este marcat cu modificatorul SAFE , activitatea va fi repornită, în caz contrar, activitatea este terminată.

Mediu de rulare

Informații despre tipurile de runtime

Numai tipurile structurale (matrice, înregistrări, obiecte) au informații de tip run-time (meta-informații). Meta-informația este stocată într-o structură specială numită Descriptor de tip . Descriptorul de tip conține date despre tipurile și numele variabilelor și câmpurilor, un tabel de moștenire, un tabel de metode virtuale și tabele de interfețe implementate .

Managementul memoriei

Active Oberon utilizează gestionarea automată a memoriei folosind un colector de gunoi în timp real întreruptibil (preemptabil) [13] , bazat pe metoda Mark and Sweep. Garbage collector rulează pe un fir separat, iar activitățile (threads-urile) care au o prioritate mai mare decât prioritatea activității garbage collector pot întrerupe execuția acestuia. În acest caz, arborele obiectului este înghețat. În prezent, numai entitățile în timp real pot întrerupe activitatea colectorului de gunoi, alocarea dinamică a memoriei este interzisă în ele , iar compilatorul monitorizează acest lucru.

Gestionarea memoriei se bazează pe utilizarea zonelor de memorie tastate . O astfel de secțiune stochează un pointer către un descriptor de tip . Folosind informațiile despre tipul de rulare găsite în descriptorul de tip, colectorul de gunoi găsește variabilele și câmpurile tipului de referință și marchează blocurile către care indică. Cu alte cuvinte, colectorul de gunoi nu trebuie să verifice fiecare valoare de tip pointer pentru a vedea dacă este un pointer valid pe heap  - folosind informațiile furnizate de descriptorul de tip, știe exact ce elemente să proceseze, ceea ce crește semnificativ viteza si precizia muncii si reduce sarcina procesului.colectarea gunoiului. Pentru a accelera alocarea memoriei, zonele libere sunt plasate pe Listele libere care conțin blocuri de memorie de anumite dimensiuni.

Variabilele de tip referință marcate cu modificatorul UNTRACED sunt indicatori care nu pot fi urmăriți . Astfel de indicatori nu sunt urmăriți de garbage collector și locațiile de memorie la care se referă pot fi recuperate în orice moment dacă au fost alocate de mediul de rulare și nu există referințe accesibile la ele care să fie luate în considerare de garbage collector. Adesea, astfel de modificatori sunt folosiți pentru a trata memoria alocată în afara timpului de execuție Active Oberon sau cu pointeri nesiguri.

Gestionarea activității obiectului

Mediul de rulare este responsabil pentru alocarea timpului CPU, se asigură (împreună cu compilatorul) că nu există mai mult de o activitate în domeniul exclusiv, se asigură că condițiile AWAIT sunt verificate în timp util și că activitățile suspendate sunt reluate. Expresiile condiției de continuare dintr-un obiect sunt reevaluate la toate punctele de ieșire din domeniile exclusive. Aceasta înseamnă că schimbarea stării unui obiect în afara domeniului exclusiv de aplicare nu determină recalcularea condițiilor. Când mai multe activități concurează pentru aceeași zonă exclusivă, atunci activitățile cu condiții îndeplinite sunt luate în considerare înaintea celor care doresc doar să intre în aria protejată [3] [14] .

Conectarea și inițializarea modulelor

Active Oberon nu are mijloacele pentru a controla direct încărcarea și descărcarea dinamică a modulelor. Limba oferă doar o secțiune de import ( IMPORT ), care conține o listă de pluginuri și o secțiune de inițializare a modulelor. Runtime trebuie să se asigure că plug-in-urile sunt conectate și inițializate înainte ca modulul curent să fie inițializat. Conectarea dinamică a unui modul se realizează prin mecanismul de legătură dinamică . Un modul nu poate fi descărcat până când nu este referit din lista de conexiuni a altui modul încărcat. Astfel, pentru a elimina problema referințelor circulare, modulele ar trebui să fie descărcate în ordinea inversă a încărcării.

Gestionarea erorilor și excepțiilor

Modulul Capcane oferă gestionarea centralizată a excepțiilor. Parametrii acceptați de instrucțiunile ASSERT și HALT pot fi utilizați pentru a clasifica excepția.

După gestionarea excepției în modulul Capcane , timpul de execuție caută secțiuni de finalizare garantată în FINAL și le transferă controlul pentru a efectua operațiunile finale.

Dacă activitatea este marcată cu modificatorul SAFE și nu există nicio secțiune FINALY în corpul obiectului , activitatea este repornită, în caz contrar, activitatea este încheiată.

API-ul de rulare oferă posibilitatea de a vă seta propriul handler de excepții.

Extensii de limbă

Exemple de programe

Salut Lume!

MODUL Hello World ; IMPORTKernelLog ; _ ÎNCEPE KernelLog . String ( "Bună ziua, lume!" ); SFÂRȘIT Bună lume .

Rezolvarea problemei clasice a furnizorului și consumatorului

MODUL BoundedBuffers ; TIP Item * = OBIECTUL ; Buffer * = OBIECTUL VAR h , n : INTEGER ; B : ARRAY * OF Item ; PROCEDURA Obține * (): Articol ; VAR x : Articol ; ÎNCEPE { EXCLUSIV } Așteptați ( n # 0 ); (*bufferul nu este gol*) x := B [ h ]; h := ( h + 1 ) MOD LEN ( B ); DEC ( n ); RETURN x END Obține ; PROCEDURĂ Pune * ( x : Item ); ÎNCEPE { EXCLUSIV } AWAIT ( n # LEN ( B )); (* bufferul nu este plin *) B [( h + n ) MOD LEN ( B )] := x ; INC ( n ) END Put ; PROCEDURE & Init ( max : INTEGER ); BEGIN (*inițializator*) NOU ( B , max ); h : = 0 n := 0 END Init ; END Buffer ; END BoundedBuffers .

Link -uri

Vezi și

Note

  1. Pagina de proiect C# activă Arhivată 4 septembrie 2011.
  2. ↑ 1 2 J. Gutknecht. Peștii chiar au nevoie de telecomandă? A Proposal for Self-Active Objects in Oberon., 1997.
  3. ↑ 1 2 3 P.J. Muller. Sistem de obiecte active. Proiectare și implementare multiprocesor. — ETH Zurich, 2002., Diss. ETH #14755.
  4. Florian Negele. Combinând programarea fără blocare cu multitasking cooperativ pentru un sistem portabil de rulare cu multiprocesor, ETH Zurich, 2014, Diss. ETH nr. 22298
  5. Florian Negele. A2 Concurrency Framework, ETH Zurich, 3 iunie 2009
  6. ↑ 1 2 P. Brinch Hansen. multiprogramare structurată. Comunicările ACM, 15(7), iulie 1972
  7. P. Brinch Hansen. principiile sistemului de operare. Prentice Hall, 1973.
  8. ↑ 1 2 C.AR Hoare. Monitoare: un concept de structurare a sistemului de operare. Communications of the ACM, 17(10):549-557, octombrie 1974.
  9. OJ Dahl. Monitoare Revizuite. În A.W. Roscoe, editor, A Classical Mind - Eseuri în onoarea lui C.A.R. Hoare. Prentice Hall,
    1994.
  10. JL Keedy. Despre structurarea sistemelor de operare cu monitoare. ACM Operating Systems Review, 13(1), ianuarie 1979.
  11. N. Wirth. Modula: un limbaj pentru multiprogramare modulară. Software - Practică și experiență, 7:3-35, 1977.
  12. N. Wirth. Utilizarea Modula. Software - Practică și experiență, 7:37-65, 1977.
  13. Ulrike Glavitsch. Colectarea gunoiului în timp real în A2. Institutul de sisteme informatice, ETH Zurich
  14. P. Reali. Raport privind limbajul Oberon activ. — ETH Zurich, 2004.