Sistem de operare în timp real - Real-time operating system

Un sistem de operare în timp real ( RTOS ) este un sistem de operare (OS) destinat să servească aplicații în timp real care procesează datele pe măsură ce intră, de obicei fără întârzieri ale tamponului . Cerințele de timp de procesare (inclusiv orice întârziere a sistemului de operare) sunt măsurate în zecimi de secunde sau în pași de timp mai scurți. Un sistem în timp real este un sistem legat de timp care are constrângeri de timp bine definite și fixe. Prelucrarea trebuie făcută în limitele definite, altfel sistemul va eșua. Acestea sunt fie bazate pe evenimente, fie în timp . Sistemele bazate pe evenimente comută între sarcini pe baza priorităților lor, în timp ce sistemele de partajare a timpului schimbă sarcina pe baza întreruperilor de ceas . Majoritatea RTOS utilizează un algoritm de planificare preventivă .

Caracteristici

O caracteristică cheie a unui RTOS este nivelul consistenței sale în ceea ce privește timpul necesar pentru acceptarea și finalizarea sarcinii unei cereri ; variabilitatea este „ jitter ”. Un sistem de operare „hard” în timp real (Hard RTOS) are mai puține jitter decât un sistem de operare „soft” în timp real (Soft RTOS). Răspunsul târziu este un răspuns greșit într-un RTOS greu, în timp ce un răspuns târziu este acceptabil într-un RTOS soft. Scopul principal de proiectare nu este un randament ridicat , ci mai degrabă o garanție a unei categorii de performanță slabă sau dură . Un RTOS care poate îndeplini, de regulă sau în general, un termen limită este un sistem de operare în timp real, dar dacă poate îndeplini un termen determinist , este un sistem de operare în timp real greu.

Un RTOS are un algoritm avansat pentru programare . Flexibilitatea programatorului permite o orchestrare mai largă, a computerului, a priorităților proceselor, dar un sistem de operare în timp real este dedicat mai frecvent unui set restrâns de aplicații. Factorii cheie într-un sistem de operare în timp real sunt o latență minimă de întrerupere și o latență minimă de comutare a firului ; un sistem de operare în timp real este apreciat mai mult pentru cât de repede sau cât de predictibil poate răspunde decât pentru cantitatea de muncă pe care o poate efectua într-o anumită perioadă de timp.

Vedeți comparația sistemelor de operare în timp real pentru o listă cuprinzătoare. De asemenea, consultați lista sistemelor de operare pentru toate tipurile de sisteme de operare.

Filozofiile de proiectare

Un RTOS este un sistem de operare în care timpul necesar procesării unui stimul de intrare este mai mic decât timpul scurs până la următorul stimul de intrare de același tip.

Cele mai comune modele sunt:

  • Condus de evenimente - schimbă sarcinile numai atunci când un eveniment cu prioritate mai mare are nevoie de service; numită prioritate preventivă sau planificare prioritară.
  • Partajarea timpului - comută sarcinile la o întrerupere regulată la ceas și la evenimente; numit round robin .

Proiectele de partajare a timpului schimbă sarcinile mai des decât este strict necesar, dar oferă multitasking mai ușor, oferind iluzia că un proces sau un utilizator are utilizarea exclusivă a unei mașini.

Proiectele timpurii ale procesorului aveau nevoie de multe cicluri pentru a schimba sarcinile în timpul cărora CPU nu putea face nimic altceva util. Deoarece comutarea a durat atât de mult timp, sistemele de operare timpurii au încercat să minimizeze pierderea timpului procesorului evitând comutarea inutilă a sarcinilor.

Programare

În modele tipice, o sarcină are trei stări:

  1. Rularea (executarea pe CPU);
  2. Gata (gata de executare);
  3. Blocat (așteaptă un eveniment, I / O de exemplu).

Majoritatea sarcinilor sunt blocate sau gata de cele mai multe ori, deoarece, în general, o singură sarcină poate rula la un moment dat per CPU . Numărul de elemente din coada pregătită poate varia foarte mult, în funcție de numărul de sarcini pe care sistemul trebuie să le îndeplinească și de tipul de planificator pe care îl folosește sistemul. Pe sistemele non-preventive mai simple, dar totuși multitasking, o sarcină trebuie să renunțe la timpul său pe CPU pentru alte sarcini, ceea ce poate face ca coada pregătită să aibă un număr mai mare de sarcini generale în starea gata de executare ( foamete de resurse ) .

De obicei, structura de date a listei gata din planificator este concepută pentru a minimiza cel mai rău interval de timp petrecut în secțiunea critică a planificatorului, timp în care preențiunea este inhibată și, în unele cazuri, toate întreruperile sunt dezactivate, dar alegerea structurii datelor depinde și de numărul maxim de sarcini care pot fi pe lista pregătită.

Dacă nu există niciodată mai mult de câteva sarcini pe lista pregătită, atunci o listă dublă legată de sarcini pregătite este probabil optimă. Dacă lista gata conține de obicei doar câteva sarcini, dar conține ocazional mai multe, atunci lista ar trebui să fie sortată în funcție de prioritate. În acest fel, găsirea sarcinii cu cea mai mare prioritate de executat nu necesită repetarea întregii liste. Inserarea unei sarcini necesită apoi parcurgerea listei gata până la atingerea fie a sfârșitului listei, fie a unei sarcini cu prioritate mai mică decât cea a sarcinii care este inserată.

Trebuie să aveți grijă să nu inhibați preempțiunea în timpul acestei căutări. Secțiunile critice mai lungi ar trebui împărțite în bucăți mici. Dacă apare o întrerupere care pregătește o sarcină cu prioritate ridicată în timpul inserării unei sarcini cu prioritate scăzută, acea sarcină cu prioritate ridicată poate fi inserată și executată imediat înainte ca sarcina cu prioritate scăzută să fie inserată.

Timpul de răspuns critic, numit uneori timpul de întoarcere, este timpul necesar pentru a pune la coadă o nouă sarcină pregătită și pentru a restabili starea sarcinii cu cea mai mare prioritate. Într-un RTOS bine conceput, pregătirea unei noi sarcini va dura între 3 și 20 de instrucțiuni pentru fiecare intrare gata de coadă, iar restaurarea sarcinii gata cu cea mai mare prioritate va dura între 5 și 30 de instrucțiuni.

În sistemele mai avansate, sarcinile în timp real împărtășesc resursele de calcul cu multe sarcini non-în timp real, iar lista pregătită poate fi în mod arbitrar lungă. În astfel de sisteme, o listă pregătită pentru planificare implementată ca listă legată ar fi inadecvată.

Algoritmi

Unii algoritmi de planificare RTOS utilizate în mod obișnuit sunt:

Comunicarea intertask și partajarea resurselor

Un sistem de operare multitasking precum Unix este slab la sarcini în timp real. Planificatorul acordă cea mai mare prioritate lucrărilor cu cea mai mică cerere de pe computer, deci nu există nicio modalitate de a vă asigura că o lucrare critică în timp va avea acces la resurse suficiente. Sistemele multitasking trebuie să gestioneze partajarea resurselor de date și hardware între mai multe sarcini. De obicei, nu este sigur ca două sarcini să acceseze simultan aceeași resursă specifică de date sau hardware. Există trei abordări comune pentru rezolvarea acestei probleme:

Mascare / dezactivare temporară a întreruperilor

Sistemele de operare cu scop general nu permit de obicei programelor utilizatorului să mascheze (dezactiveze) întreruperile , deoarece programul utilizatorului ar putea controla CPU atât timp cât dorește. Unele procesoare moderne nu permit codului modului utilizatorului să dezactiveze întreruperile, deoarece un astfel de control este considerat o resursă cheie a sistemului de operare. Multe sisteme încorporate și RTOS, cu toate acestea, permit aplicației în sine să ruleze în modul kernel pentru o eficiență mai mare a apelurilor de sistem și, de asemenea, permite aplicației să aibă un control mai mare asupra mediului de operare fără a necesita intervenția sistemului de operare.

Pe sistemele cu un singur procesor, o aplicație care rulează în modul kernel și întreruperi de mascare este cea mai mică metodă generală pentru a preveni accesul simultan la o resursă partajată. În timp ce întreruperile sunt mascate și sarcina curentă nu efectuează un apel de blocare a sistemului de operare, sarcina curentă are utilizarea exclusivă a procesorului, deoarece nicio altă sarcină sau întrerupere nu poate prelua controlul, astfel încât secțiunea critică este protejată. Când sarcina iese din secțiunea critică, trebuie să demasceze întreruperile; întreruperile în așteptare, dacă există, vor fi apoi executate. Întreruperile de mascare temporară trebuie făcute numai atunci când cea mai lungă cale prin secțiunea critică este mai scurtă decât latența maximă de întrerupere dorită . De obicei, această metodă de protecție este utilizată numai atunci când secțiunea critică este doar câteva instrucțiuni și nu conține bucle. Această metodă este ideală pentru protejarea registrelor bit-mapate hardware atunci când biții sunt controlați de sarcini diferite.

Mutexes

Când resursa partajată trebuie rezervată fără a bloca toate celelalte sarcini (cum ar fi așteptarea scrierii memoriei Flash), este mai bine să folosiți mecanisme disponibile și pe sistemele de operare de uz general, cum ar fi un mutex și mesaje interprocese supravegheate de OS. Astfel de mecanisme implică apeluri de sistem și, de obicei, invocă codul de dispecerat al sistemului de operare la ieșire, astfel încât, de obicei, iau sute de instrucțiuni CPU pentru a executa, în timp ce întreruperile de mascare pot dura doar o instrucțiune pe unele procesoare.

Un mutex (non-recursiv) este fie blocat, fie deblocat. Când o sarcină a blocat mutex-ul, toate celelalte sarcini trebuie să aștepte ca mutex-ul să fie deblocat de proprietar - firul original. O sarcină poate seta un timp de așteptare pentru un mutex. Există mai multe probleme bine-cunoscute cu proiectele bazate pe mutex, cum ar fi inversarea prioritară și blocaje .

În inversarea priorității, o sarcină cu prioritate ridicată așteaptă deoarece o sarcină cu prioritate redusă are un mutex, dar sarcinii cu prioritate mai mică nu i se acordă timp CPU pentru a-și termina activitatea. O soluție tipică este de a avea sarcina care deține un mutex „moștenește” prioritatea celei mai mari sarcini de așteptare. Dar această abordare simplă devine mai complexă atunci când există mai multe niveluri de așteptare: sarcina A asteapta un mutex blocat de sarcina B , care așteaptă pentru un mutex blocat de sarcina C . Gestionarea mai multor niveluri de moștenire determină rularea altor coduri în context cu prioritate ridicată și, prin urmare, poate provoca înfometarea firelor cu prioritate medie.

Într-un blocaj , două sau mai multe sarcini blochează mutex fără expirări și apoi așteaptă pentru totdeauna mutexul celeilalte sarcini, creând o dependență ciclică. Cel mai simplu scenariu de blocare apare atunci când două sarcini blochează alternativ două mutex, dar în ordinea opusă. Blocajul este prevenit printr-un design atent.

Trimiterea mesajului

Cealaltă abordare a partajării resurselor este ca sarcinile să trimită mesaje într-o schemă organizată de transmitere a mesajelor . În această paradigmă, resursa este gestionată direct de o singură sarcină. Atunci când o altă sarcină dorește să interogheze sau să manipuleze resursa, aceasta trimite un mesaj sarcinii de gestionare. Deși comportamentul lor în timp real este mai puțin clar decât sistemele de semafor , sistemele simple bazate pe mesaje evită majoritatea pericolelor de blocare a protocolului și, în general, se comportă mai bine decât sistemele de semafor. Cu toate acestea, sunt posibile probleme precum cele ale semaforelor. Inversarea priorității poate apărea atunci când o sarcină lucrează la un mesaj cu prioritate redusă și ignoră un mesaj cu prioritate mai mare (sau un mesaj care provine indirect dintr-o sarcină cu prioritate ridicată) în coada sa de mesaje primite. Blocajele protocolului pot apărea atunci când două sau mai multe sarcini se așteaptă reciproc pentru a trimite mesaje de răspuns.

Întrerupeți gestionarii și programatorul

Întrucât un handler de întrerupere blochează executarea sarcinii cu cea mai mare prioritate și din moment ce sistemele de operare în timp real sunt concepute pentru a menține latența firelor la un nivel minim, handlerele de întrerupere sunt de obicei menținute cât mai scurt posibil. Manipulatorul de întreruperi diferă orice interacțiune cu hardware-ul, dacă este posibil; în mod obișnuit, tot ceea ce este necesar este să recunoașteți sau să dezactivați întreruperea (astfel încât aceasta să nu mai apară din nou când se va întoarce tratatorul de întrerupere) și să anunțați o sarcină că trebuie să lucrați. Acest lucru se poate face prin deblocarea unei sarcini a driverului prin eliberarea unui semafor, setarea unui steag sau trimiterea unui mesaj. Un planificator oferă adesea posibilitatea de a debloca o sarcină din contextul de gestionare a întreruperilor.

Un sistem de operare menține cataloage de obiecte pe care le gestionează, cum ar fi fire, mutexe, memorie și așa mai departe. Actualizările la acest catalog trebuie să fie strict controlate. Din acest motiv, poate fi problematic atunci când un handler de întrerupere apelează o funcție OS în timp ce aplicația este în acțiunea de a face acest lucru. Funcția OS apelată de la un handler de întrerupere ar putea găsi baza de date a obiectelor într-o stare inconsistentă din cauza actualizării aplicației. Există două abordări majore pentru a rezolva această problemă: arhitectura unificată și arhitectura segmentată. RTOS-urile care implementează arhitectura unificată rezolvă problema prin simpla dezactivare a întreruperilor în timp ce catalogul intern este actualizat. Dezavantajul este că latența de întrerupere crește, putând pierde întreruperile. Arhitectura segmentată nu efectuează apeluri directe ale sistemului de operare, ci delegă lucrările legate de sistemul de operare unui handler separat. Acest handler rulează la o prioritate mai mare decât orice thread, dar mai mic decât handlerele de întrerupere. Avantajul acestei arhitecturi este că adaugă foarte puține cicluri pentru a întrerupe latența. Ca rezultat, sistemele de operare care implementează arhitectura segmentată sunt mai previzibile și pot face față unor rate de întrerupere mai mari comparativ cu arhitectura unificată.

În mod similar, modul de gestionare a sistemului pe hardware compatibil x86 poate dura mult timp înainte de a reveni la controlul sistemului de operare.

Alocare de memorie

Alocarea memoriei este mai importantă într-un sistem de operare în timp real decât în ​​alte sisteme de operare.

În primul rând, pentru stabilitate nu pot exista scurgeri de memorie (memorie care este alocată, dar nu eliberată după utilizare). Dispozitivul ar trebui să funcționeze la nesfârșit, fără a fi nevoie niciodată de o repornire. Din acest motiv, alocarea dinamică a memoriei nu este privită. Ori de câte ori este posibil, toată alocarea de memorie necesară este specificată static la momentul compilării.

Un alt motiv pentru a evita alocarea dinamică a memoriei este fragmentarea memoriei. Cu alocarea și eliberarea frecventă a unor mici bucăți de memorie, poate apărea o situație în care memoria disponibilă este împărțită în mai multe secțiuni și RTOS este incapabil să aloce un bloc continuu suficient de mare de memorie, deși există suficientă memorie liberă. În al doilea rând, viteza de alocare este importantă. O schemă standard de alocare a memoriei scanează o listă legată de lungime nedeterminată pentru a găsi un bloc de memorie liber adecvat, care este inacceptabil într-un RTOS, deoarece alocarea memoriei trebuie să aibă loc într-un anumit interval de timp.

Deoarece discurile mecanice au timpi de răspuns mult mai lungi și mai imprevizibili, schimbarea pe fișierele de disc nu este utilizată din aceleași motive ca alocarea RAM discutată mai sus.

Algoritmul simplu de dimensiuni fixe funcționează destul de bine pentru sistemele simple încorporate datorită cheltuielilor sale reduse.

Vezi si

Referințe