Heim  >  Artikel  >  Backend-Entwicklung  >  Golang-Mutex zugrunde liegende Implementierung

Golang-Mutex zugrunde liegende Implementierung

WBOY
WBOYOriginal
2023-05-10 19:04:05728Durchsuche

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.

  1. Die Goroutine, die die Unlock()-Methode aufruft, muss die Goroutine sein, die den Mutex hält.

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.

  1. Mutex nicht kopieren

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.

  1. Versuchen Sie, den freien Wettbewerb um Sperren zu vermeiden. Bei der gleichzeitigen Programmierung bedeutet der freie Wettbewerb um Sperren, dass eine andere Goroutine weiterhin versucht, die Sperre zu erhalten, anstatt in der Warteschlange zu warten. Dies führt zu einer Verschwendung von CPU-Ressourcen und sollte so weit wie möglich vermieden werden.
Kurz gesagt, Sperren sind ein leistungsstarkes Werkzeug zum Schutz gemeinsam genutzter Ressourcen und spielen eine sehr wichtige Rolle bei der gleichzeitigen Programmierung. Durch diesen Artikel verstehen wir das zugrunde liegende Implementierungsprinzip von Mutex sowie einige Missverständnisse, die bei der Verwendung von Mutex beachtet werden müssen. In der tatsächlichen Entwicklung sollten wir die Vorteile von Mutex voll ausnutzen, um verschiedene Probleme zu vermeiden, die bei der gleichzeitigen Programmierung auftreten können.

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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn