Sobes.tech
Middle

Cos'è la starvation (carestia) nel contesto della multithreading?

sobes.tech AI

Risposta dell'AI

Stato in cui uno o più goroutine (thread, processi) non accedono mai a una risorsa (ad esempio, un mutex, un canale) di cui hanno bisogno per continuare l'esecuzione, mentre altri goroutine accedono costantemente a questa risorsa. Ciò avviene a causa di una pianificazione ingiusta o di meccanismi di sincronizzazione inefficienti, come priorità o blocchi eccessivi.

Esempio:

package main

import (
	"fmt"
	"sync"
	"time"
)

var (
	mu      sync.Mutex
	counter int
)

func worker(id int) {
	for {
		mu.Lock() // Proteggiamo la risorsa (counter)
		// Qui può verificarsi fame se altre goroutine
		// continuamente catturano il mutex e lo mantengono a lungo.
		counter++
		fmt.Printf("Lavoratore %d ha aumentato il contatore a %d\n", id, counter)
		time.Sleep(10 * time.Millisecond) // Simulazione di lavoro
		mu.Unlock()
		// Aggiungiamo una piccola pausa per permettere allo scheduler di cambiare contesto
		time.Sleep(1 * time.Millisecond)
	}
}

func main() {
	for i := 0; i < 5; i++ {
		go worker(i)
	}

	// Il programma funzionerà indefinitamente,
	// ma alcuni worker potrebbero soffrire di fame
	// a seconda dello scheduler e del carico.
	select {}
}

Per minimizzare la fame si applicano:

  • Lock equi (fair locks): Garantisce che i thread ottengano accesso alla risorsa in ordine di richiesta.
  • Casualità: Introduzione di casualità nella scelta del thread che accederà alla risorsa.
  • Timeout: Impostare limiti di tempo per l'attesa di una risorsa.
  • Prevenzione dell'inversione di priorità: Evitare situazioni in cui un processo ad alta priorità aspetta uno a bassa priorità.

In Go, i mutex standard non garantiscono equità, il che può portare a fame in determinate condizioni.