Golang中如何避免代码中的死锁问题

Golang中如何避免代码中的死锁问题

func main() {
//var sharedlock sync.Mutex
var wg sync.WaitGroup

defer wg.Done()

worker := func() {

	for i := 0; i < 100000; i++ {
		fmt.Printf("%v\n", i)

	}

}

go worker()
wg.Add(1)
wg.Wait()

}

我遇到这个问题: 所有goroutine都处于休眠状态 - 死锁!

3 回复

谢谢!你最棒

更多关于Golang中如何避免代码中的死锁问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


defer wg.Done() 会在主函数结束时被调用。我认为你忘记将 Done 函数放入工作函数中。

你调用了 Add(1),并在没有调用 Done() 的情况下调用了 Wait()

func main() {
//var sharedlock sync.Mutex
var wg sync.WaitGroup
worker := func() {
    defer wg.Done()
	for i := 0; i < 100000; i++ {
        //pass
	}
}

go worker()
wg.Add(1)
wg.Wait()

在您提供的代码中,死锁问题主要源于sync.WaitGroup的错误使用方式。以下是具体分析和修复方案:

问题分析:

  1. defer wg.Done()被错误地放置在main函数中,而不是在goroutine内部执行
  2. wg.Add(1)在goroutine启动后才调用,存在竞态条件
  3. goroutine完成后没有调用wg.Done()来通知WaitGroup

修正后的代码:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup

	worker := func() {
		defer wg.Done() // 确保在goroutine结束时调用
		for i := 0; i < 100000; i++ {
			fmt.Printf("%v\n", i)
		}
	}

	wg.Add(1) // 在启动goroutine前先增加计数器
	go worker()
	
	wg.Wait() // 等待所有goroutine完成
}

关键修复点:

  1. 正确的WaitGroup使用顺序:
wg.Add(1)    // 先增加计数器
go worker()  // 再启动goroutine
  1. 在goroutine内部调用Done:
defer wg.Done() // 使用defer确保函数返回时一定会执行

避免死锁的最佳实践:

  • 确保wg.Add()在启动goroutine之前调用
  • 使用defer wg.Done()来保证即使发生panic也能正确释放计数器
  • 避免在多个goroutine中并发调用wg.Add()
  • WaitGroup的计数器不能为负数

另一个常见死锁场景的示例:

// 错误的锁使用方式
var mu sync.Mutex
func deadlockExample() {
    mu.Lock()
    // 某些操作...
    mu.Lock() // 第二次加锁会导致死锁
    mu.Unlock()
    mu.Unlock()
}

// 正确的做法:使用sync.RWMutex
var rwmu sync.RWMutex
func correctExample() {
    rwmu.RLock()
    // 读操作...
    rwmu.RUnlock()
    
    rwmu.Lock()
    // 写操作...
    rwmu.Unlock()
}

通过遵循这些WaitGroup的正确使用模式,可以有效避免代码中的死锁问题。

回到顶部