2012-12-17 10 views
13

Oto niektóre tła:
Potrzebuję zmiennej licznika udostępnianej między procedurami go, używanej do czegoś takiego jak nieszczelne wiadro. Wiem, że istnieje przykład nieszczelnego zasobnika w Effective Go, sekcja współbieżna, ale liczba, którą muszę śledzić, może być bardzo duża i uważam, że nieefektywne jest wykorzystywanie wielu elementów w kanale do jej śledzenia. Zastanawiam się więc nad wykorzystaniem zmiennej współdzielonej między różnymi procedurami do śledzenia liczby.Czy operatory inkrementacji są w trybie atomowym na x86?

Rozumiem, że bez jawnej konfiguracji wszystkie procedury wykonywania są mapowane na jeden wątek. Ale jeśli przypiszę więcej niż jeden wątek do programu na komputerze wielordzeniowym, czy operatory inkrementacji są atomowe? Czy to samo dotyczy różnych typów danych (int32, float32 itd.) Na różnych urządzeniach (x86_32, x86_64, arm)?

Aby być bardziej konkretnym, co jeśli mam counter += 1000 w jednej rutynie i counter -= 512 w innej procedurze, a te dwie procedury działają w dwóch wątkach? Czy muszę się martwić o bezpieczeństwo wątków? Czy mam założyć zamki na counter?

Odpowiedz

16

Nie, nigdy nie należy przyjmować przyrostu atomowego. Użyj atomowych funkcji dodatkowych lub muteksu.

Załóżmy:

import "sync/atomic" 
var counter = new(int32) 

Jeden goroutine mógłby zrobić atomic.AddInt32(counter, 1000) podczas gdy inny zrobił atomic.AddInt32(counter, -512) bez mutex.

Jeśli wolisz używać mutex:

import "sync" 
var counter int32 
var mutex sync.Mutex 

func Add(x int32) { 
    mutex.Lock() 
    defer mutex.Unlock() 
    counter += x 
} 
+0

Wow. Dzięki! Nie zauważyłem, że jest 'sync/atomic'. To znacznie ułatwia! –

Powiązane problemy