背景

项目中遇到死锁,使用搜索引擎搜索goroutine堆栈中出现的“sync.runtime_Semacquire deadlock”时,搜到一篇说sync.WaitGroup死锁,特此记录一下

当然项目中的问题不是这个导致的,是sync.RWMutex重入导致的

问题复现

func TestReLock(t *testing.T) {
var wg sync.WaitGroup
ch := make(chan int, 1000)
for i := 0; i < 1000; i++ {
wg.Add(1)
go doSomething(i, wg, ch)
}
wg.Wait()
fmt.Println("all done")
for i := 0; i < 1000; i++ {
dd := <-ch
fmt.Println("from ch:"+strconv.Itoa(dd))
}
} func doSomething(index int, wg sync.WaitGroup, ch chan int) {
defer wg.Done()
//fmt.Println("start done:" + strconv.Itoa(index))
//time.Sleep(20 * time.Millisecond)
ch <- index
}

分析

在golang中结构体传参是传值,而不是传引用,从而在doSomething函数中接收到的是sync.WaitGroup的一个复制,而不是主线程中定义的变量,所以大家都不是操作的同一个对象,因此主线程无法等到WaitGroup完成。

因此解决办法很简单,改成传引用即可,如下所示:

func doSomething(index int, wg *sync.WaitGroup, ch chan int)

noCopy介绍

在测试上面的错误使用示例的时候,会发现IDE在关键词sync.WaitGroup上显示高亮,并提示“'doSomething' passes lock by value: type 'sync.WaitGroup' contains 'interface{}' which is 'sync.Locker' ”,也就是说IDE其实提示了使用不正确。

仔细看sync.WaitGroup实现,会发现其中封装了一个noCopy对象

type WaitGroup struct {
noCopy noCopy // 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
// 64-bit atomic operations require 64-bit alignment, but 32-bit
// compilers do not ensure it. So we allocate 12 bytes and then use
// the aligned 8 bytes in them as state, and the other 4 as storage
// for the sema.
state1 [3]uint32
}

  noCopy也是一个结构体,并且实现了Locker接口

type noCopy struct{}

// Lock is a no-op used by -copylocks checker from `go vet`.
func (*noCopy) Lock() {}
func (*noCopy) Unlock() {}

  所以在golang中,如果一个结构体希望禁止用户做值拷贝,可以在结构体中使用一个noCopy变量,golang中有sync.Cond/sync.waitGroup/sync.Pool中使用了noCopy。其实golang中是禁止Locker接口值拷贝,所以sync.Mutex和sync.RWMutex等等类型如果传值也会提示该错误。

golang sync 包中:
sync.Cond
sync.Pool
sync.WaitGroup
sync.Mutex
sync.RWMutex
- ……
禁止拷贝,

golang 没有禁止对实现sync.Locker接口的对象实例赋值进行报错,只是在使用go vet 做静态语法分析时,会提示错误。

参考资料

https://stackoverflow.com/questions/13566065/why-my-golang-channel-raise-dead-lock-error

sync.WaitGroup的使用以及坑

golang sync.WaitGroup错误使用导致死锁以及noCopy结构体介绍的更多相关文章

  1. Golang Sync.WaitGroup 使用及原理

    Golang Sync.WaitGroup 使用及原理 使用 func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.A ...

  2. Golang sync.WaitGroup的用法

    0x01 介绍 经常会看到以下了代码: 12345678910111213 package main import ( "fmt" "time") func m ...

  3. golang sync.WaitGroup

    //阻塞,直到WaitGroup中的所以过程完成. import ( "fmt" "sync" ) func wgProcess(wg *sync.WaitGr ...

  4. golang(07)结构体介绍

    golang支持面向对象的设计,一般支持面向对象的语言都会有class的设计,但是golang没有class关键字,只有struct结构体.通过结构体达到类的效果,这叫做大成若缺,其用不弊. stru ...

  5. golang sync.WaitGroup bug

    注意,这个结构体,要是想在函数之间传来传去的话,必须要使用指针....... 这个结构体里没有 指针,这个类型可以说没有“引用特性”. 被坑了一晚上.特此记录.

  6. golang-----golang sync.WaitGroup解决goroutine同步

    go提供了sync包和channel来解决协程同步和通讯.新手对channel通道操作起来更容易产生死锁,如果时缓冲的channel还要考虑channel放入和取出数据的速率问题. 从字面就可以理解, ...

  7. Golang结构体struct的使用(结构体嵌套, 匿名结构体等)

    转自: https://studygolang.com/articles/11313 golang中是没有class的,但是有一个结构体struct,有点类似,他没有像java,c++中继承的概念,但 ...

  8. Golang的sync.WaitGroup 实现逻辑和源码解析

    在Golang中,WaitGroup主要用来做go Routine的等待,当启动多个go程序,通过waitgroup可以等待所有go程序结束后再执行后面的代码逻辑,比如: func Main() { ...

  9. golang 的 sync.WaitGroup

    WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成. 官方对它的说明如下: A WaitGroup waits for ...

  10. golang的sync.WaitGroup使用示例

    下面一段代码 len(m) 不一定会打印为 10,为什么?.如果想要 len(m) 打印为 10,应该怎么修改代码? func main() { const N = 10 m := make(map[ ...

随机推荐

  1. 论文笔记:Access Path Selection In A Relational Database Management System

    论文笔记:Access Path Selection In A Relation Database Management System 这篇文章是 1979 年由 IBM 发表的.主要介绍了 Syst ...

  2. Markdown 基础语法 备忘录

    在vscode中使用Markdown先要安装一些插件: Markdown Preview Enhanced Paste Image LimfxCodeEX Code Spell Checker 一级标 ...

  3. android studio 查看工程所有动画资源

  4. Unit mysqld.service could not be found.

    具体命令 service mysqld status systemctl status mysqld 结果 Unit mysqld.service could not be found. 查看mysq ...

  5. C#动态创建对象和其属性

    dynamic contact = new ExpandoObject(); contact.Name = "Patrick Hines"; contact.Phone = &qu ...

  6. 安装centos7 报错no controller found踩坑

    安装centos7.9时出现如上报错,特记录解决方法: 1.查看硬盘 出现如上报错时,耐心等待,等错误提醒不断滚动时,一会出现命令行输入界面,输入命令: [root@localhost ~]# ls ...

  7. 【10】python之条件判断

    Python 条件语句是通过一条或多条语句的执行结果(True 或者 False)来决定执行的代码块. Python中没有switch – case语句,也没有三元运算符. 1.if 语句 Pytho ...

  8. gym102586C Sum Modulo

    题意: 给你 \(n,m,k\) 以及\(p_i(1\le i\le n)\) ,保证 \(\sum p_i=1\) 你有一个数 \(X\),一开始 \(X=0\) 每次你会生成一个随机数 \(A\) ...

  9. 1144. 递减元素使数组呈锯齿状 (Medium)

    问题描述 1144. 递减元素使数组呈锯齿状 (Medium) 给你一个整数数组 nums,每次 操作 会从中选择一个元素并 将该元素的值减少 1. 如果符合下列情况之一,则数组 A 就是 锯齿数组: ...

  10. locust socektio协议压测

    # -*-coding:UTF-8 -*- from locust import HttpLocust, TaskSet, task, TaskSequence, Locust, events imp ...