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.