Στην τεχνολογία λογισμικού το **busy-waiting** ή **spinning** είναι μια τεχνική που χρησιμοποιείται όταν προγραμματίζουμε με νήματα/threads. Η ιδέα είναι ότι το νήμα τρέχει ένα βρόχο επανάληψης μέχρι να ικανοποιηθεί κάποια συνθήκη. Για παράδειγμα μια κατάσταση *busy-waiting* είναι όταν μέσω ενός βρόχου επανάληψης ελέγχουμε αν ο χρήστης έχει εισάγει κάτι από το πληκτρολόγιο. Με την ίδια τεχνική μπορεί να δημιουργηθεί προσαρμοσμένη καθυστέρηση. Στον προγραμματισμό μικροελεγκτών δημιουργείται ένας γυμνός βρόχος (χωρίς να εκτελεί κώδικα) και ανάλογα με την ταχύτητα του μικροελεγκτή δημιουργεί μια καθυστέρηση στο εκτελέσιμο πρόγραμμα. Η τεχνική *busy waiting* χρησιμοποιείται στα spinlocks όπου ένα νήμα τρέχει ένα ατέρμονο βρόχο περιμένοντας πρόσβαση σε ένα πόρο του συστήματος. Όσο ο πόρος δεν είναι διαθέσιμος το νήμα βρίσκεται σε κατάσταση αναμονής ή *busy-waiting*.

Παράδειγμα C
------------

Στο παρακάτω παράδειγμα στην γλώσσα C έχουμε 2 νήματα (POSIX νήματα ) που διαμοιράζονται το ακέραιο **i** (κοινός πόρος). Το πρώτο νήμα υλοποιεί τη τεχνική *busy-waiting* όπου τρέχει ένα ατέρμονο *γυμνό* βρόχο περιμένοντας αλλαγή στην τιμή που ακέραιου **i**:

```
/\* $ gcc busywait.c -o busywait -Wall -lpthread -pthread \*/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
 
volatile int i = 0; /\* i είναι κοινός πόρος και είναι προσβάσιμο από όλες τις συναρτήσεις.
 Έχει οριστεί ως volatile, γιατί μπορεί να αλλάξει τιμή κάτι το οποίο
 δεν είναι προβλέψιμο από τον μεταγλωττιστή, όπως από ένα άλλο νήμα \*/
 
/\* f1 χρησιμοποιεί ένα spinlock περιμένοντας μέχρι να πάρει το i διαφορετική τιμή από 0. \*/
static void \*f1(void \*p)
{
 while (i==0) {
 /\* "γυμνός" ατέρμονος βρόχος χωρίς να τρέχει εκτελέσιμο κώδικα \*/
 } 
 printf("η τιμή του i άλλαξε σε %d.\n", i);
 return NULL;
}

static void \*f2(void \*p) {
 sleep(60); /\* μπες σε διαδικασία αναμονής "sleep" για 60 δευτερόλεπτα \*/
 i = 99;
 printf("η t2 άλλαξε την τιμή του i σε %d.\n", i);
 return NULL;
}

int main() {
 int rc;
 pthread\_t t1, t2;

 rc = pthread\_create(&t1, NULL, f1, NULL);
 if (rc != 0) {
 fprintf(stderr,"pthread f1 απέτυχε\n");
 return EXIT\_FAILURE;
 }
 
 rc = pthread\_create(&t2, NULL, f2, NULL);
 if (rc != 0) {
 fprintf(stderr,"pthread f2 απέτυχε\n");
 return EXIT\_FAILURE;
 }
 
 pthread\_join(t1, NULL);
 pthread\_join(t2, NULL);
 puts("Όταν τα νήματα ολοκληρώθηκαν.");
 return 0;
}

```

Μετά από 60 δευτερόλεπτα το νήμα t2 αλλάζει την τιμή του **i** από 0 σε 99 και τότε το νήμα t1 το οποίο βρίσκεται σε κατάσταση *busy-wait* μέσω του "γυμνού" (χωρίς κώδικα) βρόχου *while (i==0) { }* βγαίνει από την αναμονή και εμφανίζει το μήνυμα *η τιμή του i άλλαξε σε 99.*.

```
$ ./busywait
η t2 άλλαξε την τιμή του i σε 99.
η τιμή του i άλλαξε σε 99.
Όταν τα νήματα ολοκληρώθηκαν.

```

Παραπομπές
----------

1. ↑  Valvano, Jonathan W. (2012). *Embedded systems : introduction to the arm® cortex(TM)-M3* (1st ed. έκδοση). United States: [s.n.] σελ. 345. ISBN 9781477508992. CS1 maint: Extra text (link)
2. ↑  (ed.), Ming-Yang Kao (2007). *Encyclopedia of algorithms*. New York, NY: Springer. σελ. 190. ISBN 978-0-387-30770-1. CS1 maint: Extra text: authors list (link)
3. ↑  Ιppolito, Greg. «POSIX thread (pthread) libraries». Carnegie Mellon School of Computer Science.