Concurrent Map: защити доступ с помощью мьютекса
Условие задачи
Реализуй потокобезопасную структуру 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
}