2012-12-17 8 views
13

Hier ist ein Hintergrund:
Ich brauche eine Zählervariable zwischen Go Routinen, für so etwas wie eine Leaky-Bucket verwendet. Ich weiß, dass es in Effective Go ein Beispiel für Leaky-Bucket gibt, aber die Anzahl, die ich verfolgen muss, kann sehr groß sein, und ich finde es ineffizient, die Anzahl der Elemente in einem Kanal zu verwenden, um sie zu verfolgen. Also überlege ich, eine gemeinsame Variable zwischen verschiedenen Routinen zu verwenden, um die Nummer zu verfolgen.Sind Inkrementoperatoren in Go atomic auf x86?

Ich verstehe, dass ohne explizite Konfiguration alle Go-Routinen auf einen Thread zugeordnet sind. Aber wenn ich dem Programm auf einem Multicore-Computer mehr als einen Thread zuweise, sind Inkrementoperatoren atomar? Ist es für verschiedene Datentypen (int32, float32 usw.) auf verschiedenen Maschinen gleich (x86_32, x86_64, arm)?

Um konkreter zu sein, Was passiert, wenn ich counter += 1000 in einer Routine und counter -= 512 in einer anderen Routine habe, und die beiden Routinen passiert in zwei Threads ausgeführt werden? Muss ich mich um Thread-Sicherheit kümmern? Soll ich Schlösser an der counter anziehen?

Antwort

16

Nein, Inkrement sollte niemals als atomar angenommen werden. Verwenden Sie die atomaren Additionsfunktionen oder einen Mutex.

Nehmen wir an:

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

One goroutine atomic.AddInt32(counter, 1000) tun könnte, während ein anderer atomic.AddInt32(counter, -512) ohne Mutex tat.

Wenn Sie lieber ein Mutex verwenden würde:

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

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

Wow. Vielen Dank! Ich habe nicht bemerkt, dass es "sync/atomic" gibt. Das macht die Dinge viel einfacher! –