背景

项目中遇到死锁,使用搜索引擎搜索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. 4K60帧!RayLink远程控制软件如何帮助设计师远程办公?

    司机在家能远程工作吗?大写的"能"!!!如果你听说过司机远程办公,那你一定对下面这张图不陌生~ (远程办公的叉车司机) 这张图展示的是负责在库房工作的叉车司机在非办公区域远程办公的 ...

  2. css 启动页 loading动画

    <div class="index-html-loader"> <div class="text">Loading...</div ...

  3. python爬虫--房产数据爬取并保存本地

    import requestsimport csvfrom bs4 import BeautifulSoupheaders={'user-agent':'Mozilla/5.0 (Windows NT ...

  4. 19c 滚动升级

    一.环境说明   节点1 节点2 IP 192.168.3.77 192.168.3.88 DB 版本 Oracle 19.6.0.0.0 Oracle 19.6.0.0.0 OS 主机名 oadb1 ...

  5. ssh_remote_without_password

    2 machines, 1 called client , 1 called server , server need static ip address. client connects serve ...

  6. 学生网络创业交流会-2021年office

    1.课程的讲解之前,先来对题目进行分析,首先需要在考生文件夹下,将Wrod素材.docx文件另存为Word.docx,后续操作均基于此文件,否则不得分. 2.这一步非常的简单,打开下载素材文件,在[文 ...

  7. jquery的网络引用地址

    http://apps.bdimg.com/libs/jquery/1.6.4/jquery.js http://apps.bdimg.com/libs/jquery/1.6.4/jquery.min ...

  8. php excel导出列超过26个字母处理

    /** * String from columnindex * * @param int $pColumnIndex Column index (base 0 !!!) * @return strin ...

  9. Python 用exec来获取字符串所对应的字典

    Python 用exec来获取字符串所对应的字典 Python exec 问题的提出 想要遍历两个结构相似的字典,但是不想采用字典内嵌套字典的方式,所以想要通过一个列表,该列表包含字典名称.也就是通过 ...

  10. 在Unity3D中开发的坦克履带模拟器Tank Track Simulator

    为了在Unity游戏中比较真实地模拟坦克履带的运动,本人便开发了这款Tank Track Simulator插件 特点 比较真实地模拟了坦克履带的运动. 本插件中包含了一辆M1A2坦克模型,已经将这个 ...