Heim > Artikel > Backend-Entwicklung > Golang-Mutex zugrunde liegende Implementierung
Golang ist eine effiziente und prägnante Programmiersprache, und ihre gute Leistung und Benutzerfreundlichkeit spiegeln sich in der Anwendung der gleichzeitigen Programmierung wider. Bei der gleichzeitigen Programmierung ist Mutex ein sehr verbreiteter Synchronisationsmechanismus. Er kann den gegenseitigen Zugriff auf gemeinsam genutzte Ressourcen in einer Multithread-Umgebung sicherstellen und gleichzeitig Race-Bedingungen vermeiden (d. h. unvorhersehbare Ergebnisse, wenn mehrere Threads gleichzeitig auf gemeinsam genutzte Ressourcen zugreifen). In diesem Artikel wird das zugrunde liegende Implementierungsprinzip von Mutex vorgestellt.
1. Definition von Mutex
In Golang ist Mutex ein Synchronisationsmechanismus, der zum Schutz des sich gegenseitig ausschließenden Zugriffs auf gemeinsam genutzte Ressourcen verwendet wird. Es enthält zwei Methoden: Lock() und Unlock(), die zum Sperren bzw. Entsperren von Mutex verwendet werden. Wenn ein Thread die Mutex-Sperre erhält, werden andere Threads blockiert, bis die Sperre aufgehoben wird.
2. Die zugrunde liegende Implementierung von Mutex
In Golang basiert die zugrunde liegende Implementierung von Mutex hauptsächlich auf einer Struktur namens sync.Mutex. Die Implementierung von Mutex wird durch die CAS-Operation (Compare-And-Swap) implementiert, die auf der atomaren Operation der zugrunde liegenden Hardware basiert.
Mutex-Struktur ist wie folgt definiert:
type Mutex struct { state int32 sema *uint32 // 信号量 } const ( mutexLocked = 1 << iota // mutex is locked ) func (m *Mutex) Lock() { // Fast path: 这里如果加锁成功,就直接返回 if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) { return } // Slow path : 防止出现busy spinning,将当前协程加入等待队列,然后调用runtime.semacquire继续sleep。 sema := m.sema if sema == nil { sema = new(uint32) m.sema = sema } runtime_Semacquire(sema) } func (m *Mutex) Unlock() { // Fast path: 这里如果释放锁成功,就直接返回 if atomic.CompareAndSwapInt32(&m.state, mutexLocked, 0) { return } // Slow path: 如果锁还被持有,则调用sync.runtime_Semrelease继续唤醒协程。 sema := m.sema if sema == nil { panic("sync: unlock of unlocked mutex") } runtime_Semrelease(sema, false, 1) }
Mutex-Struktur enthält zwei Felder, einen Zustand und ein Semaphor-Sema. Unter diesen gibt der Status den Status der Sperre an, mutexLocked gibt an, dass sie gesperrt ist, und andere Werte geben an, dass sie nicht gesperrt ist. Sema wird verwendet, um Goroutinen zu koordinieren, die auf Sperren warten.
Wenn in der Mutex.Lock()-Methode der aktuelle Mutex nicht gesperrt ist, verwenden Sie die atomare Operation CompareAndSwapInt32, um den Status von 0 in mutexLocked zu ändern, und kehren Sie nach Erfolg direkt zurück. Andernfalls lassen Sie die aktuelle Goroutine in die Warteschlange eintreten und Rufen Sie die Laufzeit auf. Die Methode semacquire() weckt sie. Wenn in der Mutex.Unlock()-Methode der aktuelle Mutex gesperrt ist, verwenden Sie die atomare Operation CompareAndSwapInt32, um den Status von mutexLocked auf 0 zu ändern, und kehren Sie nach Erfolg direkt zurück. Andernfalls wird eine Ausnahme ausgelöst, die anzeigt, dass der aktuelle Mutex nicht gesperrt ist gesperrt.
Es gibt schnelle und langsame Pfade sowohl in den Methoden Mutex.Lock() als auch Mutex.Unlock(). Der schnelle Pfad bedeutet, dass die Sperre schnell erhalten oder über CAS aufgehoben werden kann, wenn der Sperrstatus nicht belegt ist. Der langsame Pfad bedeutet, dass, wenn der Sperrstatus belegt ist, die aktuelle Goroutine zur Warteschlange hinzugefügt werden muss und die Methode sema.acquire() aufgerufen werden muss, um sie in den Ruhezustand zu versetzen oder andere Goroutinen in der Warteschlange aufzuwecken.
3. Missverständnisse bei der Verwendung von Mutex
In Golang ist Mutex ein sehr häufig verwendeter Synchronisierungsmechanismus, aber während der Verwendung gibt es einige häufige Missverständnisse, die wir vermeiden müssen.
Wenn eine Goroutine versucht, einen Mutex freizugeben, den sie nicht hält, löst das Programm eine Panik aus. Mutex-Sperren sollen den gegenseitigen Zugriff auf gemeinsam genutzte Ressourcen sicherstellen. Wenn eine Goroutine die Sperre aufheben kann, kann ihre gegenseitige Exklusivität nicht garantiert werden.
Mutex-Sperre ist ein Zeigertyp. Wenn Sie die Sperrvariable kopieren müssen, sollten Sie die Zeigerkopie verwenden. Andernfalls führt dies dazu, dass zwei unabhängige Mutex-Instanzen denselben Status teilen, was zu unerwartetem Verhalten führen kann.
Das obige ist der detaillierte Inhalt vonGolang-Mutex zugrunde liegende Implementierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!