it-praxisportal/courses/go/12_mutex_und_thread_safety/aufgabe.go

135 lines
3.4 KiB
Go

package main
import (
"errors"
"fmt"
"sync"
"sync/atomic"
)
// ============================================================================
// 🚀 GO 12: MUTEX, RWMUTEX & ATOMIC OPERATIONS
// ============================================================================
// 🎯 TODO 1: Definiere das Struct 'SafeCache'
// Felder:
// - mu sync.RWMutex
// - items map[string]string
type SafeCache struct {
// TODO: Struct-Felder ergänzen
mu sync.RWMutex
items map[string]string
}
// NewSafeCache erstellt eine initialisierte SafeCache-Instanz.
func NewSafeCache() *SafeCache {
return &SafeCache{
items: make(map[string]string),
}
}
// 🎯 TODO 2a: Set(key, val string) - Schreibt einen Wert thread-safe in den Cache.
// Anforderungen:
// - Nutze c.mu.Lock() und per defer c.mu.Unlock()
func (c *SafeCache) Set(key, val string) {
// TODO: Lock setzen, in items schreiben
}
// 🎯 TODO 2b: Get(key string) (string, bool) - Liest einen Wert thread-safe aus dem Cache.
// Anforderungen:
// - Nutze c.mu.RLock() und per defer c.mu.RUnlock()
func (c *SafeCache) Get(key string) (string, bool) {
// TODO: RLock setzen, Wert und Existent-Flag zurückgeben
return "", false
}
// 🎯 TODO 2c: Delete(key string) - Löscht einen Schlüssel thread-safe.
func (c *SafeCache) Delete(key string) {
// TODO: Lock setzen, delete(c.items, key)
}
// 🎯 TODO 2d: Len() int - Gibt die Anzahl der Elemente thread-safe zurück.
func (c *SafeCache) Len() int {
// TODO: RLock setzen, len(c.items) zurückgeben
return 0
}
// 🎯 TODO 3: Implementiere 'AtomicCounter' mit lock-freiem sync/atomic
type AtomicCounter struct {
val int64
}
// Inc erhöht den Zähler um 1 und gibt den neuen Wert zurück.
func (a *AtomicCounter) Inc() int64 {
// TODO: atomic.AddInt64(&a.val, 1)
return 0
}
// Add erhöht den Zähler um delta und gibt den neuen Wert zurück.
func (a *AtomicCounter) Add(delta int64) int64 {
// TODO: atomic.AddInt64(&a.val, delta)
return 0
}
// Value gibt den aktuellen Stand atomar zurück.
func (a *AtomicCounter) Value() int64 {
// TODO: atomic.LoadInt64(&a.val)
return 0
}
// Reset setzt den Zähler atomar auf 0 zurück.
func (a *AtomicCounter) Reset() {
// TODO: atomic.StoreInt64(&a.val, 0)
}
// 🎯 TODO 4: Implementiere 'SafeBankAccount' mit sync.Mutex
type SafeBankAccount struct {
mu sync.Mutex
balance float64
}
// Deposit zahlt einen Betrag sicher ein.
func (b *SafeBankAccount) Deposit(amount float64) {
// TODO: b.mu.Lock(), Guthaben erhöhen
}
// Withdraw bucht einen Betrag ab, sofern ausreichend Guthaben vorhanden ist.
// Gibt bei unzureichendem Guthaben einen Fehler zurück: errors.New("insufficient funds").
func (b *SafeBankAccount) Withdraw(amount float64) error {
// TODO: b.mu.Lock(), Guthaben prüfen und abbuchen oder Fehler werfen
return nil
}
// Balance gibt das aktuelle Guthaben zurück.
func (b *SafeBankAccount) Balance() float64 {
// TODO: b.mu.Lock(), Guthaben zurückgeben
return 0.0
}
func main() {
fmt.Println("=== Go 12: Mutex & Thread Safety ===")
cache := NewSafeCache()
var wg sync.WaitGroup
// Parallele Schreiber
for i := 0; i < 50; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
cache.Set(fmt.Sprintf("key-%d", id), fmt.Sprintf("val-%d", id))
}(i)
}
// Parallele Leser
for i := 0; i < 50; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
cache.Get(fmt.Sprintf("key-%d", id))
}(i)
}
wg.Wait()
fmt.Printf("Cache erfolgreich befüllt. Gesamtelemente: %d\n", cache.Len())
}