Beskonačna petlja

**Beskonačna petlja** (ili **petlja bez granica**) je niz uputstava u računarskom programu koji ulaze u beskonačnu petlju, bilo zbog petlje koja nema završno stanje, i.e. završetak petlje je zavistan od stanja koje se ne može ostvariti, ili kriterijum završetka petlje izaziva njen ponovni početak. U starijim operativnim sistemima sa kooperativnim multitaskovanjem, beskonačne petlje obično uzrokuju da ceo sistem prestane da reaguje. Sa sadašnjim preovlađujućim preventivnim multitasking modelom, beskonačne petlje uzrokuju da program konzumira sve dostupno vreme procesora, ali ga korisnik obično može zaustaviti. Petlje aktivnog čekanja se takođe ponekad nazivaju "beskonačnim petljama". Jedan mogući uzrok "zamrzavanja" računara je beskonačna petlja; ostali uključuju mlaćenje (engl.thrashing), zastoj i greška segmentacije.

## Planirano protiv neplaniranog petljanja
Petljanje ponavlja niz instrukcija sve dok određeni uslov nije ispunjen. Beskonačna petlja nastaje kada se nikada ne ispuni neki od uslova, zbog prisutne karakteristike petlje.

### Namerno petljanje
Postoje nekoliko slučaja kada je to poželjno ponašanje. Na primer, igrice zasnovane na konzolama obično nemaju uslov izlaza u glavnoj petlji, jer ne postoji operativni sistem iz kog bi se moglo izaći; petlja radi sve dok se konzola ne isključi.

Starinski čitač kartica, oprema za zapisivanje jedinica, bi se bukvalno zaustavio kada bi obrada kartice bila završena, pošto nije bilo potrebe da hardver nastavi sa radom, sve dok se ne učita nova gomila programskih kartica.

Nasuprot tome, moderni interaktivni računari zahtevaju da računar stalno nadgleda korisničke unose ili aktivnost uređaja, tako da na nekom osnovnom nivou postoji beskonačan proces idle petlje koja mora da nastavi sve dok se uređaj ne isključi ili resetuje. U Apollo Guidance Računaru, na primer, ova spoljna petlja se nalazila u Exec programu, i ako računar ne bi imao nikakvog posla, petlja bi se startovala kako bi radila lažni posao koji bi isključio  svetlosni pokazivač"računarske aktivnosti".

Moderni računari takođe obično ne zaustavljaju procesor ili ciklične satove matične ploče kada se "sruše". Umesto toga, vraćaju se grešci koja prikazuje poruke operatoru, i ulazi u beskonačnu petlju čekajući korisnika da ili odgovori na upit kako bi nastavio, ili da resetuje uređaj.

### Nenamerno petljanje
Najčešće se termin koristi za one situacije kada to nije ciljani rezultatat;to je, kada se desi "bag". Ovakve greške su najčešće kod programera početnika, ali mogu se desiti i kod iskusnijih programera takođe,jer su njihovi uzroci dosta suptilni.

Jedan čest uzrok, na primer,je taj kada programer pokuša da ponovi nešto nad zbirkom stavki kao što je povezana lista, izvršavajući kod petlje jednom za svaku stavku. Nepravilno formiranje veze može stvoriti referentnu petlju u listi, gde je jedan element liste povezan sa onim koji se dogodio ranije na listi. Ovaj deo liste ulazi u krug, što dovodi da program petlja zauvek.

Dok se većina beskonačnih petlji mogu naći u blizini inspekcije koda, ne postoji opšti metod za određivanje da li će se dati program ikada zaustaviti ili će raditi zauvek; ovo je često kod problema zaustavljanja.

## Prekid
Sve dok sistem reaguje, beskonačne petlje često mogu biti prekinute slanjem signala u procesu (kao što je SIGINT u Unix), ili prekid u procesoru, što uzrokuje da trenutni proces bude prekinut. Ovo se može uraditi u menadžeru zadataka, u terminalu sa komandom Control-C , ili koristeći  "kill" komandu ili poziv sistema. Međutim, ovo ne radi uvek, jer proces možda ne reaguje na signala ili procesor može biti u neprekidnom stanju, kao u "Cyrix coma bug "(prouzrokovan preklapanjem neprekidnim instrukcijama u instrukcionom "cevovodu"). U nekim slučajevima ostali signali kao što je SIGKILL može raditi, pošto ne zahtevaju proces da se oglašava, dok u drugim slučajevima petlja ne može biti ugašena gašenjem sistema.

## Jezička podrška
Beskonačne petlje se mogu sprovesti koristeći različite konstrukcije kontrole toka. Najčešće, u nestrukturnom programiranju ovo je skok nazad ( "goto "), dok je u strukturnom programiranju  neodređena petlja  (while petlja) postavljena da se nikad ne završi, ili izostavljajući stanje ili eksplicitno postavljajući na tačno, kao `while (true).``..`.

Neki jezici imaju posebne konstrukcije za beskonačne petlje, tipično izostavljajući stanje iz beskonačne petlje. Primeri uključuju Ada (`loop... end loop`), Fortran (`DO.``.. ``END DO`), Go (`for {... }`), i Ruby (`loop do... end`).

## Primeri namernih beskonačnih petlji
Najjednostavniji primeri (u C):
```c
int main()
{
  for (;;); // or while (1);
}
```
Obrazac `for (;;)` za beskonačnu petlju je tradicionalan, koji se pojavljuje u standarnoj referenci * [[S Programski jezik]]*, and i često se izgovara "zauvek".

Ovo je petlja koja će štampati "Beskonačna Petlja" bez zaustavljanja.

Jednostavan primer u Bejsik-u :
```gwbasic
10 PRINT "INFINITE LOOP"
20 GOTO 10
```
Jednostavan primer u Aembler x86:
```asm
loop:
 ; Code to loop here
  jmp loop
```
Ostali primeri u DOS-u
```asm
:A
goto :A
```
Ovde je petlja sasvim očigledna, jer poslednja linija bezuslovno šalje izvršenje nazad na prvo.

Primer u Pajton-u
```python
while True:
    print("Infinite Loop")
```
Primer u Baš-u
```bash
$ while true; do echo "Infinite Loop"; done
```
Primer u Perl-u
```perl
print "Infinite Loop\n" while 1
```


## Primeri nenamernih beskonačnih petlji

### Matematičke greške
Ovde je primer beskonačne petlje u Vižual bejsiku:
```vb
dim x as integer
do while x < 5
  x = 1
  x = x + 1
loop
```
Ovo stvara situaciju gde `x` nikada neće biti veće od 5, pošto je na početku petlje promenljivoj `x` data vrednost 1, stoga će se iteracija uvek završiti sa 2 i petlja nikad neće prestati. To se može popraviti premeštanjem `x = 1` instrukcije izvan petlje. Esencijalno ova petlja nalaže računaru da nastavi s dodavanjem 1 na 1 dok se ne dosegne vrednost 5. Pošto je 1+1 uvek jednako 2, do toga nikad ne dolazi.

U nekim jezicima, zbunjenost programera zbog matematičkih simbola može dovesti do nenamerne beskonačne petlje. Na primer, ovde je odlomak u S:
```c
#include <stdio.h>

int main(void)
{
   int a = 0;
   while (a < 10) {
      printf("%d\n", a);
      if (a = 5)
         printf("a jednako 5!\n");
      a++;
   }
   return 0;
}
```
Očekivani izlaz su brojevi od 0 do 9, sa prekidom "a jednako 5!" između 5 i 6. Međutim, u redu "`if (a = 5)`" iznad, programer je pomešao = (dodelu) sa == (testom jednakosti) operatora. Umesto toga, ovo će dodeliti vrednost 5 `a`  u ovom delu programa. Stoga, `a` nikada neće biti u mogućnosti da napreduje do 10, i ovo petlja se ne može prekinuti.

### Rukovanje nad greškama sa promenljivom
Neočekivano ponašanje u proceni završnog stanja može takođe prouzrokovati problem. Evo primera (u C):
```c
float x = 0.1;
while (x != 1.1) {
  printf("x = %f\n", x);
  x = x + 0.1;
}
```
Na nekim sistemima, ova petlja će se izvršiti deset puta kao što je i očekivano, ali se na ostalim sistemima neće izvršiti. Problem je u tome što petlja okončava uslov (x != 1.1) testa za tačne jednakosti dve vrednosti, i način po kom su vrednosti zastupljene u mnogim računarima će učiniti da test ne uspe, jer se ne može predstaviti tačna vrednost 1.1.

Isto se može desiti i u  Pajtonu:
```python
x = 0.1
while x != 1:
    print x
    x += 0.1
```
Zbog verovatnoće testova za  jednakost ili nejednakost koji su neočekivano neispravni, sigurnije je koristiti više-od ili manje-od testove kada se radi o  "floating-point "vrednostima. Na primer, umesto da se testira da li je  `x` jednako 1.1, moglo bi se proveriti da li  je (x , ili (x , koji bi sigurno izašli nakod određenog broja ponavljanjae. Još jedan način da se popravi ovaj primer bio bi uz korišćenje celog broja kao indeks petlje, brojeći broj ponavljanja koji su bili izvršeni.

Sličan problem se dešava često u numeričkoj analizi:  da bi se izračunao određeni rezultat, ponavljanje je namenjeno da se izvrši sve dok greška ne bude manja od izabrane tolerancije. Međutim, zbog grešaka zaokruživanja tokom ponavljanja, određena tolerancija ne može biti nikada dostignuta, što rezultuje beskonačnom petljom.

## Višepartijska petlja
Iako su beskonačne petlje u jednom programu obično lake za predvideti, petlja izazvana od strane više lica je mnogo teže predvideti. Zamislite server koji uvek odgovara sa greškom u vidu poruke ako ne razume traženi zahtev. Očigledno, ne postoji mogućnost za beskonačnom petljom na serveru, ali ako su tu dva servera (A i B), i A primi poruku o nepoznatom tipu iz B, onda A odgovara sa greškom u vidu poruke serveru B, B ne razume poruku u odgovara serveru A sa njegovom porukom, A ne razume poruku od B i šalje još jednu grešku u vidu poruke, i tako u beskonačnost. Jedan čest primer ove situacije je petlja elektronske pošte.

## Kvazi-beskonačne petlje
Kvazi-beskonačna petlja je petlja koja se pojavljuje u beskonačnosti, ali je samo veoma duga petlja.

### Nemoguć prestanak uslova
Primer for petlje u C:
```c
unsigned int i;
for (i = 1; i != 0; i++) {
  /* loop code */
}
```
Čini se da će ovo ići u nedogled, ali ustavari će vrednost `i` na kraju dostići maksimalnu skladišnu vrednost u `unsigned int` i dodavanje broja 1 tom broju će se završiti sa 0, okončavajući petlju. Stvarna granica `i` zavisi od sistema i kompilatora koji se koristi. Sa proizvoljno preciznom računicom, ova petlja će nastaviti sa radom sve dok računarska memorija ne može više sadržati `i`. Ako je `i` pripican ceo broj, više nego ne pripisan ceo broj, prelivanje neće biti definisano. U tom slučaju, petlja može biti optimizovana u beskonačnu petlju.

### Beskonačna rekurzija
Beskonačna rekurzija je specijalan slučaj beskonačne petlje koja je prouzrokovana rekurzijom . Najtrivijalniji primer ovog uslova Ω u lambda računu , pokazan je dole u Scheme:
```scheme
(define Ω
  (let ([ω (lambda (f) (f f))])
    (ω ω)))
```
Ω je beskonačna rekurzija, stoga nema normalnu formu. Kada se koristi strukturna rekurzija, beskonačne rekuzije su obično izazvane nedostatkom glavnog slučaja ili neispravnim induktivnim korakom. Primer pogrešne strukturne rekurzije:
```scheme
(define (sum-from-1-to n)
  (+ n (sum-from-1-to (sub1 n))))
```
Funkcija *sum-from-1-to* će ostati bez prostora, pošto rekurzija nikada ne prestaje — beskonačna je. Kako bi se ispravio problem, dodat je glavni slučaj.
```scheme
(define (sum-from-1-to' n)
  (cond
    [(= n 1) 1]
    [else (+ n (sum-from-1-to' (sub1 n)))]))
```
Ovoj izmenjenoj funkciji će nestati prostora samo ako je *n* manje od 1 ili ako je *n* preveliko; pronalazač greške bi izbrisao prvi slučaj. Za informacije o rekurzivnim funkcijama koje nikada neće ostati bez prostora, pogledati "rep" rekurziju.

Vidi još: Rekurzija, za dodatno objašnjenje beskonačne rekurzije.

### Izjava prekid
 "`while (true)`" petlja na prvi pogled izgleda kao beskonačna, ali možda postoji način da se izbegne petlja kroz prekid izjavu ili kroz izjavu povratka.
Na primer u PHP:
```php
while (true) {
   if ($foo->bar()) {
      return;
   }
}
```


### Aldersonova petlja
*Aledersonova petlja je *je redak sleng ili žargosnki izraz za beskonačnu petlju gde je dostupan uslov za izlaz, ali nije dostupna trenutna realizacija koda, obično zbog greške programera. One su najčešće i najvidljivije dokom korisničkog koda debagovanja .

Kao u C- pseudokodu primer Aldersonove petlje, gde se od programa očekuje da sumira brojeve date od strane korisnika dok nula nije data, ali gde je programer koristio pogrešnog operatora:
```c
sum = 0;
while (true) {
   printf("Ubaciti broj kako bi se dodalo sumi ili 0 za izlaz");
   i = getUserInput();
   if (i * 0) { // ako je i puta 0 tačno, dodati i sumi
      sum += i; // suma se ne menja zato što je (i * 0)  0 za bilo koje i; promenilo bi ako bismo imali != u uslovu umesto *
   }
   if (sum > 100) {
      break;    // zaustavlja petlju; stanje izlaza postoji ali nikad se ne dolazi do njega zato što nikada suma nije dodata
   }
}
```
Termin je navodno dobio ime od programera koji je kodirao modalnu poruku kutije u Majkrosoft akses bez OK ili Cancel dugmeta, čime se onemogućava čitav program svaki put kada se kutija pojavi.

## Povezano
* Detekcija kruženja
* Zastoj
* Divergencija (računarstvo)
* GoTo
* Rekurzija
* Fork bomba

## Reference