Concurrent Map: защити доступ с помощью мьютекса

К задачам
Средняя
Concurrency

Условие задачи

Реализуй потокобезопасную структуру map[string]int. Нужно поддерживать методы Set, Get и Inc (увеличить значение по ключу). Воспользуйся sync.Mutex. Нельзя использовать sync.Map.

package main

import "sync"

type SafeMap struct {
    mu sync.Mutex
    m  map[string]int
}

func NewSafeMap() *SafeMap {
    return &SafeMap{
        m: make(map[string]int),
    }
}

func (s *SafeMap) Set(key string, value int) {
    // TODO
}

func (s *SafeMap) Get(key string) (int, bool) {
    // TODO
    return 0, false
}

func (s *SafeMap) Inc(key string) {
    // TODO
}

func main() {
    // протестируй с несколькими горутинами
}
package main

import "sync"

type SafeMap struct {
    mu sync.Mutex
    m  map[string]int
}

func NewSafeMap() *SafeMap {
    return &SafeMap{
        m: make(map[string]int),
    }
}

func (s *SafeMap) Set(key string, value int) {
    // TODO
}

func (s *SafeMap) Get(key string) (int, bool) {
    // TODO
    return 0, false
}

func (s *SafeMap) Inc(key string) {
    // TODO
}

func main() {
    // протестируй с несколькими горутинами
}

Подсказка

- Все методы должны блокировать доступ к мапе. - Используй defer s.mu.Unlock() для безопасности.

Решение

sync.Mutex защищает критическую секцию, обеспечивая безопасный доступ из нескольких горутин.

package main

import (
    "fmt"
    "sync"
)

type SafeMap struct {
    mu sync.Mutex
    m  map[string]int
}

func NewSafeMap() *SafeMap {
    return &SafeMap{
        m: make(map[string]int),
    }
}

func (s *SafeMap) Set(key string, value int) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.m[key] = value
}

func (s *SafeMap) Get(key string) (int, bool) {
    s.mu.Lock()
    defer s.mu.Unlock()
    val, ok := s.m[key]
    return val, ok
}

func (s *SafeMap) Inc(key string) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.m[key]++
}

func main() {
    m := NewSafeMap()
    var wg sync.WaitGroup

    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            m.Inc("counter")
        }()
    }

    wg.Wait()
    v, _ := m.Get("counter")
    fmt.Println("counter =", v) // должно быть 100
}
package main

import (
    "fmt"
    "sync"
)

type SafeMap struct {
    mu sync.Mutex
    m  map[string]int
}

func NewSafeMap() *SafeMap {
    return &SafeMap{
        m: make(map[string]int),
    }
}

func (s *SafeMap) Set(key string, value int) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.m[key] = value
}

func (s *SafeMap) Get(key string) (int, bool) {
    s.mu.Lock()
    defer s.mu.Unlock()
    val, ok := s.m[key]
    return val, ok
}

func (s *SafeMap) Inc(key string) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.m[key]++
}

func main() {
    m := NewSafeMap()
    var wg sync.WaitGroup

    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            m.Inc("counter")
        }()
    }

    wg.Wait()
    v, _ := m.Get("counter")
    fmt.Println("counter =", v) // должно быть 100
}