Što je prstenasti međuspremnik?

Prstenasti međuspremnik je također poznat kao red čekanja ili ciklički međuspremnik i uobičajeni je oblik reda čekanja. Ovo je popularan, lako implementiran standard, i iako je predstavljen kao krug, on je linearan u osnovnom kodu. Prstenasti red postoji kao niz fiksnih duljina s dva pokazivača: jedan predstavlja početak reda, a drugi - rep. Nedostatak metode je njena fiksna veličina. Za redove gdje se elementi moraju dodati ili ukloniti u sredini, a ne samo na početku i na kraju međuspremnika, najbolja je implementacija kao povezani popis.

Teorijska osnova pufera

Korisniku je lakše odabrati učinkovitu strukturu nizova nakon razumijevanja temeljne teorije. Ciferski međuspremnik je podatkovna struktura u kojoj se niz obrađuje i vizualizira u obliku petlji, tj. Indeksi se vraćaju na 0 nakon dostizanja duljine polja. To se radi s dva pokazivača na nizu: "glava" i "rep". Kada se podaci dodaju u međuspremnik, indeks smjera se pomiče prema gore. Slično tome, kada se uklone, rep se također pomiče prema gore. Definicija glave, repa, smjera kretanja, mjesta snimanja i čitanja ovisi o provedbi sheme.


Kružni odbojnici se prekomjerno učinkovito koriste za rješavanje problema potrošača. Odnosno, jedan tok izvršenja je odgovoran za proizvodnju podataka, a drugi za potrošnju. U ugrađenim uređajima s vrlo niskom i srednjom razinom, proizvođač je predstavljen u formatu ISR (informacija dobivena od senzora), a potrošač - u oblikuciklus glavnog događaja. Karakteristika cikličkih odbojnika je da se provode bez potrebe za bravama u okolini jednog proizvođača i jednog potrošača. To ih čini idealnom informacijskom strukturom za ugrađene aplikacije. Sljedeća razlika je u tome što ne postoji točan način razlikovanja popunjenog sektora od praznog. To je zato što se u oba slučaja glava stapa s repom. Postoji mnogo načina i sredstava za rješavanje problema, no većina ih čini zbunjujućom i kompliciranijom čitljivosti.


Još jedno pitanje koje se javlja u odnosu na ciklički tampon. Trebate li poništiti nove podatke ili ponovno snimiti postojeće kada je puna? Stručnjaci tvrde da ne postoji očigledna prednost jedni protiv drugih, a njegova provedba ovisi o konkretnoj situaciji. Ako su potonje relevantnije za aplikaciju, upotrijebite metodu prepisivanja. S druge strane, ako se obrađuju u načinu "prvi dolaze - prvi serviran", odbacite nove kada se popuni prstenasti međuspremnik.

Realizacija cikličkog reda

Kada je riječ o implementaciji, definirani su tipovi podataka, a zatim su metode: jezgra, push i pop. U postupcima "push" i "pop" izračunajte "takve" točke pomaka za mjesto na kojem će se odvijati trenutno snimanje i čitanje. Ako to mjesto ukazuje na rep, tada je spremnik pun i podaci se ne bilježe. Slično tome, kada je "glava" jednaka "repu", ona je prazna i iz nje se ništa ne čita.

Standardna verzija uporabe

Pomoćni postupak naziva se programskim postupkomza izdvajanje podataka iz Java kružnog me uspremnika. Trebao bi biti uključen u kritične dijelove ako kontejner čita više od jedne niti. Rep se pomiče do sljedećeg pomaka prije čitanja informacija, budući da je svaki blok jedan bajt i zadržava isti iznos u međuspremniku kada je volumen potpuno učitan. Ali u naprednijim izvedbama cikličkog pogona, odvojeni dijelovi ne moraju nužno biti iste veličine. U takvim slučajevima, oni pokušavaju spremiti i posljednji bajt, dodajući više čekova i granica. U takvim shemama, ako se rep pomiče prije čitanja, informacije koje bi se trebale čitati mogu potencijalno biti prepisane novonastalim podacima. Općenito, preporuča se prvo pročitati, a zatim pomaknuti pokazivač repa. Prvo odredite duljinu međuspremnika, a zatim stvorite instancu "circ_bbuf_t" i dodijelite pokazivač na "maxlen". U tom slučaju, spremnik mora biti globalni ili složen. Primjerice, ako vam je potreban 32-bitni međuspremnik, u privitku izvedite sljedeće (vidi sliku ispod).

Specifikacija funkcionalnih zahtjeva

Tip podataka "ring_t" bit će vrsta podataka koja sadrži pokazivač na međuspremnik, njegovu veličinu, indeks zaglavlja i repa i brojač podataka. Funkcija inicijalizacije "ring_init ()" inicijalizira međuspremnik na temelju dobivanja pokazivača na strukturu spremnika stvorenog pozivnom funkcijom s određenom veličinom. Funkcija ring_add () dodaje bajt sljedećem slobodnom prostoru u međuspremniku.Funkcija uklanjanja ring_remove () će izbrisati bajt iz najstarijeg dostupnog prostora u spremniku. Prstenasti peek u ring_peek () funkciji će pročitati broj bajtova "uint8_t" brojanja iz međuspremnika za zvono u novi, pod uvjetom kao parametar, bez uklanjanja svih vrijednosti iz spremnika. Vratit će broj stvarno pročitanih bajtova.
Ring_clear () funkcija će postaviti "Tail" jednako "Head" i učitati "0" u svim položajima međuspremnika.

Stvaranje međuspremnika u C /C ++

Zbog ograničenih resursa ugrađenih sustava, struktura podataka s cikličkim međuspremnikom može se naći u većini projekata fiksne veličine koji rade kao da je pamćenje po prirodi kontinuirano i prsten. Ne trebate mijenjati podatke jer se memorija generira i koristi, a pokazatelji za glavu /rep su ispravljeni. Prilikom stvaranja cikličke knjižnice međuspremnika, korisnici trebaju raditi s API-jem knjižnice, umjesto da izravno mijenjaju strukturu. Stoga se koristi kapsuliranje pufera za prsten na "C". Na taj način programer će uštedjeti implementaciju knjižnice, mijenjati je prema potrebi, bez potrebe da je krajnji korisnici ažuriraju.

Korisnici ne mogu raditi s pokazivačem "circular_but_t", stvarajući tip deskriptora koji se može koristiti umjesto toga. Time se eliminira potreba za pomicanjem pokazivača za implementaciju funkcije .typedefcbuf_handle_t. Programeri trebaju izgraditi API-je za biblioteku. Oni su u interakciji s bibliotekom kružnog bafera "C" koristeći neprozirni tip deskriptora,koji se stvara tijekom inicijalizacije. Obično odabirete "uint8_t" kao osnovni tip podataka. No, možete koristiti bilo koji određeni tip, vodeći računa o ispravnom rukovanju osnovnim spremnicima i broju bajtova. Korisnici komuniciraju sa spremnikom slijedeći potrebne procedure:
  • Inicijalizirajte spremnik i njegovu veličinu.
  • Ponovno postavite kružni spremnik.
  • Dodajte podatke u prstenasti međuspremnik na "C".
  • Dobijte sljedeću vrijednost iz spremnika.
  • Zatražite informacije o trenutnom broju stavki i maksimalnom kapacitetu.
  • I "puni" i "prazni" slučajevi izgledaju isto: "glava" i "rep", pokazivači su jednaki. Postoje dva pristupa koji razlikuju puni i prazni:
  • Kompletan državni rep + 1 == glava.
  • Prazna državna glava == rep.
  • Implementacija knjižničnih funkcija

    Za stvaranje kružnog kontejnera, koristite njegovu strukturu za kontrolu stanja. Za spremanje enkapsulacije, struktura je definirana unutar knjižnice .c, a ne u zaglavlju. Prilikom instaliranja, trebat ćete pratiti:
  • Osnovni podatkovni međuspremnik.
  • Maksimalna veličina.
  • Trenutni položaj glave raste s dodatkom.
  • Trenutni rep se povećava kada se ukloni.
  • Oznaka označava napunjeni spremnik ili ne. Sada kada je kontejner dizajniran, on implementira knjižnične funkcije. Svaki API zahtijeva inicijalizirani deskriptor međuspremnika. Umjesto začepljenja koda s uvjetnim izjavama, podnesite zahtjev za odobrenje kako biste izvršili zahtjeveAPI u stilu.
    Implementacija neće biti orijentirana prema trenutnom stanju ako u baznu biblioteku cikličkih spremišta nije dodana nikakva brava. Za inicijalizaciju API-ja, klijenti koji pružaju veličinu osnovnog spremnika, stoga ga kreiraju na strani knjižnice, na primjer, radi pojednostavljenja "malloc". Sustavi koji ne mogu koristiti dinamičku memoriju trebali bi promijeniti funkciju "init" kako bi koristili drugu metodu, kao što je odabir iz statičkog spremnika. Drugi je pristup razbijanje enkapsulacije, omogućujući korisnicima da statički deklariraju strukture spremnika. U ovom slučaju, "circular_buf_init" treba ažurirati da bi se uzela pokazivač ili "init", stvorila struktura stogova i vratila. Međutim, budući da je enkapsulacija poremećena, korisnici je mogu mijenjati bez knjižničnih postupaka. Nakon što je spremnik stvoren, ispunite vrijednost i prouzročite "resetiranje". Prije povratka iz "init", sustav osigurava da je spremnik u praznom stanju.

    Dodavanje i brisanje podataka

    Dodavanje i uklanjanje podataka iz spremnika zahtijeva manipulaciju iz indikatora "glava" i "rep". Kada se doda u spremnik, umetnite novu vrijednost u trenutne stranice "glave" i promicajte ih. Kada se uklone, dobivaju vrijednost trenutnog "repa" -indikatora i promiču "rep". Ako želite premjestiti indeks "rep", a također i "glavu", morate provjeriti uzrokuje li umetanje vrijednost "puna". Kada je spremnik već pun, pomaknite "rep" jedan korak ispred "glave".
    Nakon pomicanja pokazivača, ispunite "puni" -objavljivanje,provjera jednakosti "glava == rep". Modularna uporaba operatera će uzrokovati da se "glava" i "rep" vraćaju na "0" kada se dostigne maksimalna veličina. To osigurava da će "head" i "tail" uvijek biti valjane baze podataka osnovnog kontejnera podataka: "static void advance_pointer (cbuf_handle_t cbuf)". Možete stvoriti sličnu pomoćnu funkciju koja se zove kada brišete vrijednosti iz međuspremnika.

    Sučelje predložaka

    Kako bi implementacija C ++-a mogla podržati bilo koju vrstu podataka, slijedite predložak:
  • Resetirajte međuspremnik za čišćenje.
  • Dodavanje i brisanje podataka.
  • ​​
  • Provjera potpunog /praznog stanja.
  • Provjera trenutnog broja stavki.
  • Provjera ukupnog kapaciteta spremnika.
  • Kako se ne bi ostavili nikakvi podaci nakon uništavanja međuspremnika, koriste se inteligentni C ++ pokazivači kako bi se osiguralo da korisnici mogu upravljati podacima.
  • U ovom primjeru, C ++ spremnik simulira većinu logike C implementacije, ali rezultira mnogo čistijim i višekratnim dizajnom. Osim toga, C ++ spremnik koristi "std :: mutex" za pružanje trenutne implementacije. Kada kreirate klasu, odaberite podatke za glavni me uspremnik i postavite njegovu veličinu. Ovo eliminira opterećenje koje zahtijeva implementacija C. Za razliku od njega, C ++ konstruktor ne uzrokuje "resetiranje", budući da određuje početne vrijednosti članova, kružni kontejner radi u ispravnom stanju. Ponovno ponašanje vraća me uspremnik u prazno stanje. U provedbi C ++ "veličine" cikličkog spremnika i"Kapacitet" prikazuje broj stavki u redu čekanja, a ne veličinu u bajtovima.

    UART STM32 upravljački program

    Nakon pokretanja međuspremnika, on mora biti integriran u UART upravljački program. Prvo kao globalni element u datoteci, stoga je potrebno deklarirati:
  • "descriptor_rbd" i memorijsku memoriju "_rbmem: static rbd_t _rbd";
  • "statički znak _ 8".
  • Budući da je ovo UART upravljački program, gdje svaki znak mora biti 8-bitni, stvaranje niza znakova je dopušteno. Ako se koristi 9 ili 10 bitni mod, svaki element bi trebao biti "uint16_t". Kontejner se izračunava tako da se izbjegne gubitak podataka. Često moduli reda sadrže statističke podatke koji omogućuju praćenje maksimalne upotrebe. U inicijalizacijskoj funkciji "uart_init", me uspremnik se mora inicijalizirati pozivom "ring_buffer_init" i prijenosom strukture atributa svakom članu kojem su dodijeljene dogovorene vrijednosti. Ako je uspješno inicijaliziran, UART modul se izlazi iz resetiranja, prijemni prekid je dopušten u IFG2.
    Druga funkcija koju treba promijeniti je "uart_getchar". Čitanje primljenog znaka iz UART perifernog uređaja zamjenjuje se čitanjem iz reda čekanja. Ako je red prazan, funkcija se mora vratiti -1. Zatim morate implementirati UART da biste dobili ISR. Otvorite datoteku zaglavlja "msp430g2553.h", pomaknite se prema dolje do odjeljka vektora prekida, gdje vektor s imenom USCIAB0RX pronalazi. Imenovanje znači da ga koriste moduli USCI A0 i B0. Status prekida prijema USCI A0 može se očitati iz IFG2. Ako je instaliran, zastavica bi trebala biti izbrisana, a podaci u odjeljku za primanje stavljeni u međuspremnikpomoću "ring_buffer_put".

    UART pohrana podataka

    Ovo spremište pruža informacije o tome kako čitati UART podatke koristeći DMA kada je broj bajtova za primanje unaprijed nepoznat. STM32 kružna međuspremnik može raditi u različitim načinima:
  • Način pozivanja (bez DMA, bez IRQ-a) - aplikacija bi trebala testirati bitove statusa kako bi provjerila je li novi znak prihvaćen i pročitao ga dovoljno brzo da bi dobio sve bajtove. Vrlo jednostavna implementacija, ali je nitko ne koristi u stvarnom životu. Cons - to je lako propustiti primljene znakove u paketima podataka, radi samo za niske brzine prijenosa.
  • Način prekida (bez DMA) - UART prstenasti međuspremnik prekida prekid, a CPU prelazi u servisni program za obradu prijema podataka. Najrasprostranjeniji pristup u svim aplikacijama danas dobro funkcionira u srednjem rasponu. Cons - postupak prekida obrade obavlja se za svaki primljeni znak, može zaustaviti druge zadatke u mikrokontrolerima visokih performansi s velikim brojem prekida i istovremeno operativni sustav pri primanju paketa podataka.
  • Način DMA se koristi za prijenos podataka iz USART RX registra u memoriju na razini hardvera. U ovoj fazi nije potrebna interakcija s aplikacijom, osim potrebe obrade podataka primljenih od strane aplikacije. Može biti vrlo lako raditi s operativnim sustavima. Optimizirano za visoke brzine prijenosa podataka & gt; 1Mbps i aplikacije male snage, u slučaju velikih paketa podataka, može se poboljšati povećanje veličine međuspremnikafunkcionalnost.
  • Implementacija ARDUINO-a

    Arduino međuspremnik vrpce odnosi se na dizajn ploča i programsko okruženje koje se koristi za rad. Arduino jezgra je mikrokontroler serije Atmel AVR. Većinu posla obavlja AVR, a Arduino ploča oko AVR-a u mnogim aspektima pruža funkcionalnost - lako priključivanje kontakata, USB-serijsko sučelje za programiranje i komunikaciju. Mnoge redovne Arduino kartice trenutno koriste prstenasti međuspremnik s ATmega 328 starijim matičnim pločama koje koriste ATmega168 i ATmega8. Ploče poput Mega biraju složenije opcije, kao što je 1280 i slično. Što je dulji i nula brži, bolje je koristiti ARM. Postoji desetak različitih Arduino ploča s imenima. Mogu imati različite količine flash memorije, RAM-a i I /O portova s ​​AVR spremnikom.
    Varijabla "roundBufferIndex" koristi se za pohranjivanje trenutne pozicije, a pri dodavanju u međuspremnik bit će ograničeno polje.
    Ovo su rezultati izvršavanja koda. Brojevi su pohranjeni u međuspremniku, a kad su puni, počinju prepisivati. Tako možete dobiti posljednje N brojeve.
    U prethodnom primjeru, indeks je korišten za pristup trenutnoj poziciji međuspremnika, jer je dovoljan za objašnjenje operacije. Ali općenito, normalno je koristiti pokazivač. Ovo je modificirani kod za korištenje pokazivača umjesto indeksa. U biti, ista operacija kao prethodna i dobiveni rezultati su slični.

    Operacije CAS-a visokih performansi

    Disruptor jeKnjižnica visokih performansi za prijenos poruka, koju je prije nekoliko godina razvila i otvorila LMAX Exchange. Oni su stvorili ovaj softver za obradu ogromnog prometa (više od 6 milijuna TPS-a) u maloprodajnoj financijskoj trgovinskoj platformi. U 2010, svi su iznenadili sve koliko brzo bi njihov sustav mogao biti, nakon što je završio svu poslovnu logiku u jednoj niti. Iako je jedna nit bila važan koncept u njihovom rješenju, Disruptor radi u višenitnom okruženju i temelji se na prstenskom međuspremniku - streamu u kojem zastarjeli podaci više nisu potrebni, jer dolazi svježe i relevantnije. U tom slučaju, ili povratak lažne logičke vrijednosti ili zaključavanje će raditi. Ako niti jedno od ovih rješenja ne zadovoljava korisnike, može se implementirati spremnik koji se može mijenjati, ali samo kada je ispunjen, a ne samo kada proizvođač dođe do kraja polja. Promjena veličine zahtijevat će premještanje svih elemenata u novo dodijeljeni veći niz ako se koristi kao osnovna podatkovna struktura, što je naravno skupa operacija. Postoje mnoge druge stvari koje čine Disruptor brzo, kao što su poruke u batch načinu rada. Qtserialport (serijski port) međuspremnik je naslijeđen od QIODevice, može se koristiti za dobivanje različitih serijskih informacija i uključuje sve dostupne serijske uređaje. Serijski port je uvijek otvoren u monopolskom pristupu, što znači da drugi procesi ili niti ne mogu pristupiti otvorenoj serijiluke Ring buffers su vrlo korisni u programiranju za "C", na primjer, možete procijeniti tok bajtova koji dolaze kroz UART.

    Povezane publikacije