Sobes.tech
Middle

Czym jest głodzenie (starvation) w kontekście wielowątkowości?

sobes.tech AI

Odpowiedź od AI

Stan, w którym jeden lub więcej goroutine (wątki, procesy) nigdy nie uzyskuje dostępu do zasobu (np. mutex, kanał), którego potrzebują do kontynuowania działania, podczas gdy inne goroutine mają ciągły dostęp do tego zasobu. Dzieje się tak z powodu niesprawiedliwego planowania lub nieefektywnych mechanizmów synchronizacji, takich jak priorytety lub nadmierne utrzymywanie blokad.

Przykład:

package main

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

var (
	mu      sync.Mutex
	counter int
)

func worker(id int) {
	for {
		mu.Lock() // Chronimy zasób (counter)
		// Tutaj może wystąpić głodzenie, jeśli inne goroutine
		// ciągle będą przejmować mutex i długo go trzymać.
		counter++
		fmt.Printf("Pracownik %d zwiększył licznik do %d\n", id, counter)
		time.Sleep(10 * time.Millisecond) // Symulacja pracy
		mu.Unlock()
		// Dodajemy niewielkie opóźnienie, aby planista mógł się przełączać
		time.Sleep(1 * time.Millisecond)
	}
}

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

	// Program będzie działał nieskończenie długo,
	// ale niektóre goroutine mogą doświadczać głodzenia
	// w zależności od planisty i obciążenia.
	select {}
}

Aby zminimalizować głodzenie, stosuje się:

  • Sprawiedliwe blokady (fair locks): Gwarantują, że wątki uzyskują dostęp do zasobu w kolejności żądania.
  • Losowość: Wprowadzenie losowości w wybór wątku, który uzyska dostęp do zasobu.
  • Timeouty: Ustawianie ograniczeń czasowych na oczekiwanie na zasób.
  • Unikanie odwrócenia priorytetów: Unikanie sytuacji, gdy proces o wysokim priorytecie czeka na proces o niskim priorytecie.

W Go standardowe mutexy nie gwarantują sprawiedliwości, co może prowadzić do głodzenia w określonych warunkach.