MST

星途 面试题库

面试题:Go语言中互斥锁死锁预防之场景分析

在Go语言并发编程中,假设有两个goroutine,goroutine A持有互斥锁`mutexA`,并试图获取互斥锁`mutexB`;goroutine B持有互斥锁`mutexB`,并试图获取互斥锁`mutexA`,这种情况下可能会发生死锁。请编写一段代码来模拟这个场景,并阐述如何通过调整获取锁的顺序来预防死锁。
45.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

模拟死锁代码

package main

import (
    "fmt"
    "sync"
)

var (
    mutexA sync.Mutex
    mutexB sync.Mutex
)

func goroutineA(wg *sync.WaitGroup) {
    defer wg.Done()
    mutexA.Lock()
    fmt.Println("goroutine A acquired mutexA")
    mutexB.Lock()
    fmt.Println("goroutine A acquired mutexB")
    mutexB.Unlock()
    mutexA.Unlock()
}

func goroutineB(wg *sync.WaitGroup) {
    defer wg.Done()
    mutexB.Lock()
    fmt.Println("goroutine B acquired mutexB")
    mutexA.Lock()
    fmt.Println("goroutine B acquired mutexA")
    mutexA.Unlock()
    mutexB.Unlock()
}

func main() {
    var wg sync.WaitGroup
    wg.Add(2)
    go goroutineA(&wg)
    go goroutineB(&wg)
    wg.Wait()
}

预防死锁方案

通过调整获取锁的顺序来预防死锁,比如让两个goroutine都按照相同的顺序获取锁。

调整后代码

package main

import (
    "fmt"
    "sync"
)

var (
    mutexA sync.Mutex
    mutexB sync.Mutex
)

func goroutineA(wg *sync.WaitGroup) {
    defer wg.Done()
    mutexA.Lock()
    fmt.Println("goroutine A acquired mutexA")
    mutexB.Lock()
    fmt.Println("goroutine A acquired mutexB")
    mutexB.Unlock()
    mutexA.Unlock()
}

func goroutineB(wg *sync.WaitGroup) {
    defer wg.Done()
    mutexA.Lock()
    fmt.Println("goroutine B acquired mutexA")
    mutexB.Lock()
    fmt.Println("goroutine B acquired mutexB")
    mutexB.Unlock()
    mutexA.Unlock()
}

func main() {
    var wg sync.WaitGroup
    wg.Add(2)
    go goroutineA(&wg)
    go goroutineB(&wg)
    wg.Wait()
}

在上述修改后的代码中,goroutineAgoroutineB都先获取mutexA,再获取mutexB,这样就避免了死锁的发生。