**Rengaspuskuri** on tietojenkäsittelytieteessä tietorakenne.
Rengas-sanalla viitataan tapaan, jolla tiedon tallennus- ja lukupaikka kiertää puskuria. Tallennettaessa tietoa puskuriin kirjoituspaikka etenee kohti puskurin loppua. Kun kirjoituspaikka ylittää puskurin koon, se siirtyy takaisin alkuun. Tiedon lukukohta liikkuu samalla tavalla eteenpäin palaten alkuun puskurin lopussa.

Rengaspuskuria voidaan käyttää *tuottaja/kuluttaja*-mallilla tai ylikirjoitusmallilla. Tuottaja/kuluttaja-mallissa tuottaja täyttää puskurin tiedolla kunnes se täyttyy ja jää odottamaan kunnes kuluttaja saa käsitteltyä puskurissa olevan tieton. Ylikirjoitusmallissa vanhimmat tiedot ylikirjoitetaan vaikka niitä ei olisi käsitelty.
Edsger Dijkstra työskenteli tuottaja/kuluttaja-aiheen parissa 1960-luvulla ja julkaisi vuonna 1972 artikkelin *Information Streams Sharing a Finite Buffer*. 1980-luvulla esitettiin "Mesa-semantiikkaa" käyttävä ratkaisu artikkelissa *Experience with Processes and Monitors in Mesa*.

Käyttökohteita
--------------

Rengaspuskuria voidaan käyttää esimerkiksi muuntamaan tietovirtaa, joka saadaan pakettiverkon yli vaihtelevalla nopeudella muotoon, josta kiinteällä nopeudella sitä kuluttava käsittelijä saa aina samalla viiveellä seuraavan alkion käsittelyyn.

Pakettiverkossa paketit voivat saapua eri järjestyksessä ja eri aikoina eri reittejä käyttäen, josta johtuen käytännön toteutukset voivat käyttää useita muistilohkoja rengaspuskurina.

Esimerkkitoteutus
-----------------

Esimerkissä on C-kielellä tehtynä yksinkertainen rengaspuskuritoteutus, jossa on käytetty kolmea apumuuttujaa (`read_position`, `write_position` ja `buffer_len`) rengaspuskurin sisäiseen kirjanpitoon. Esimerkkitoteutus lukee ja kirjoittaa tietoa merkki kerrallaan puskuriin.

```
#include <stdio.h>

#define BUFFER\_SIZE 10

char buffer\_data[BUFFER\_SIZE];
int read\_position=0;
int write\_position=0;
int buffer\_len=0;

int ringbuffer\_insert(char data){
 if( buffer\_len < BUFFER\_SIZE){
 buffer\_data[write\_position]=data;
 buffer\_len++;
 if(++write\_position==BUFFER\_SIZE){
 write\_position=0;
 }
 return 1;
 }
 return 0;
 }

int ringbuffer\_read(char\* data){
 if(buffer\_len>0){
 \*data=buffer\_data[read\_position];
 buffer\_len--;
 if(++read\_position==BUFFER\_SIZE){
 read\_position=0;
 }
 return 1;
 }
 return 0;
}

```

### Optimointi

Rengaspuskuritoteutuksesta saa puristettua pois muutaman `if`-lauseen ja apumuuttujan, jos puskurin koko on 2:n potenssi (2, 4, 8, 16, jne.). Tällöin ei tarvita ehtoa, jossa testataan, vuotaako puskuri seuraavaksi yli, vaan voidaan käyttää bittimaskia ja vapaasti eteenpäin juoksevia luku- ja kirjoituspaikkalaskureita.

Katso myös
----------

* Linkitetty lista

Lähteet
-------

1. ↑  Lockless Ring Buffer Design *docs.kernel.org*. Viitattu 8.9.2022. (englanniksi)
2. ↑  Edsger Dijkstra: My recollections of operating system design *cs.utexas.edu*. Viitattu 13.4.2024. (englanniksi)
3. ↑  Arpaci-Dusseau, Remzi H. & Arpaci-Dusseau, Andrea C.: Condition Variables (PDF) *pages.cs.wisc.edu*. Viitattu 13.4.2024. (englanniksi)
4. ↑  The Producer-Consumer Problem & POSIX Condition Variables *cs.fsu.edu*. Viitattu 13.4.2024. (englanniksi)
5. ↑  Dan Siemon: Queueing in the Linux Network Stack  23.9.2013. Linux Journal. Viitattu 26.3.2018.