Go语言核心36讲
郝林
《Go并发编程实战》作者,前轻松筹大数据负责人
立即订阅
24054 人已学习
课程目录
已完结 54 讲
0/4登录后,你可以任选4讲全文学习。
开篇词+学习路线 (3讲)
开篇词 | 跟着学,你也能成为Go语言高手
免费
预习篇 | 写给0基础入门的Go语言学习者
50 | 学习专栏的正确姿势
模块一:Go语言基础知识 (6讲)
01 | 工作区和GOPATH
02 | 命令源码文件
03 | 库源码文件
04 | 程序实体的那些事儿(上)
05 | 程序实体的那些事儿(中)
06 | 程序实体的那些事儿 (下)
模块二:Go语言进阶技术 (16讲)
07 | 数组和切片
08 | container包中的那些容器
09 | 字典的操作和约束
10 | 通道的基本操作
11 | 通道的高级玩法
12 | 使用函数的正确姿势
13 | 结构体及其方法的使用法门
14 | 接口类型的合理运用
15 | 关于指针的有限操作
16 | go语句及其执行规则(上)
17 | go语句及其执行规则(下)
18 | if语句、for语句和switch语句
19 | 错误处理(上)
20 | 错误处理 (下)
21 | panic函数、recover函数以及defer语句 (上)
22 | panic函数、recover函数以及defer语句(下)
模块三:Go语言实战与应用 (27讲)
23 | 测试的基本规则和流程 (上)
24 | 测试的基本规则和流程(下)
25 | 更多的测试手法
26 | sync.Mutex与sync.RWMutex
27 | 条件变量sync.Cond (上)
28 | 条件变量sync.Cond (下)
29 | 原子操作(上)
30 | 原子操作(下)
31 | sync.WaitGroup和sync.Once
32 | context.Context类型
33 | 临时对象池sync.Pool
34 | 并发安全字典sync.Map (上)
35 | 并发安全字典sync.Map (下)
36 | unicode与字符编码
37 | strings包与字符串操作
38 | bytes包与字节串操作(上)
39 | bytes包与字节串操作(下)
40 | io包中的接口和工具 (上)
41 | io包中的接口和工具 (下)
42 | bufio包中的数据类型 (上)
43 | bufio包中的数据类型(下)
44 | 使用os包中的API (上)
45 | 使用os包中的API (下)
46 | 访问网络服务
47 | 基于HTTP协议的网络服务
48 | 程序性能分析基础(上)
49 | 程序性能分析基础(下)
尾声与思考题答案 (2讲)
尾声 | 愿你披荆斩棘,所向无敌
新年彩蛋 | 完整版思考题答案
Go语言核心36讲
登录|注册

27 | 条件变量sync.Cond (上)

郝林 2018-10-12
在上篇文章中,我们主要说的是互斥锁,今天我和你来聊一聊条件变量(conditional variable)。

前导内容:条件变量与互斥锁

我们常常会把条件变量这个同步工具拿来与互斥锁一起讨论。实际上,条件变量是基于互斥锁的,它必须有互斥锁的支撑才能发挥作用。
条件变量并不是被用来保护临界区和共享资源的,它是用于协调想要访问共享资源的那些线程的。当共享资源的状态发生变化时,它可以被用来通知被互斥锁阻塞的线程。
比如说,我们两个人在共同执行一项秘密任务,这需要在不直接联系和见面的前提下进行。我需要向一个信箱里放置情报,你需要从这个信箱中获取情报。这个信箱就相当于一个共享资源,而我们就分别是进行写操作的线程和进行读操作的线程。
如果我在放置的时候发现信箱里还有未被取走的情报,那就不再放置,而先返回。另一方面,如果你在获取的时候发现信箱里没有情报,那也只能先回去了。这就相当于写的线程或读的线程阻塞的情况。
虽然我们俩都有信箱的钥匙,但是同一时刻只能有一个人插入钥匙并打开信箱,这就是锁的作用了。更何况咱们俩是不能直接见面的,所以这个信箱本身就可以被视为一个临界区。
尽管没有协调好,咱们俩仍然要想方设法的完成任务啊。所以,如果信箱里有情报,而你却迟迟未取走,那我就需要每过一段时间带着新情报去检查一次,若发现信箱空了,我就需要及时地把新情报放到里面。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Go语言核心36讲》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(15)

  • 属鱼
    个人理解,不确定对不对,请老师评判一下:
    因为Go语言传递对象时,使用的是浅拷贝的值传递,所以,当传递一个Cond对象时复制了这个Cond对象,但是低层保存的L(Locker类型),noCopy(noCopy类型),notify(notifyList类型),checker(copyChecker)对象的指针没变,因此,*sync.Cond和sync.Cond都可以传递。

    作者回复: 基本正确。Locker是接口,是引用类型,nocopy是结构体,所以直接拷贝值的话,底层锁还是用的同一个,使用上容易出问题。

    2018-10-12
    13
  • hello peter
    老师, 感觉这个送信的例子似乎用chanel实现更简单.在网上也查了一些例子, 发现都可以用chanel替代. 那使用sync.Cond 的优势是什么呢, 或者有哪些独特的使用场景?

    作者回复: 优势是并发流程上的协同,chan的主要任务是传递数据。另外cond是更低层次的工具,效率更高一些,但是肯定没有chan方便。

    2018-10-26
    4
  • 文@雨路
    指针可以传递,值不可以,传递值会拷贝一份,导致出现两份条件变量,彼此之间没有联系
    2018-10-12
    3
  • ming
    多routine从信箱中获取情报, 都在等mailbox变量的值不为0的时候再把它的值变为0,
    这个 RLock 限制不了写操作,可能会有多个routine同时将 mailbox 变为0的,跟文中的场景有些不合。
    不知道我理解的有没有问题
    2018-12-17
    1
    2
  • 🤔
    需传递 *sync.Cond

    因为 Cond 结构体中的 notify 变量和 checker 变量都是值类型,传递sync.Cond 会复制值,这样两个锁保留的被阻塞的 Goroutine 就不同了。
    2019-04-09
    1
  • beiliu
    您好,老师,官方文档是建议,singal在锁住的情况下使用的“Signal唤醒等待c的一个线程(如果存在)。调用者在调用本方法时,建议(但并非必须)保持c.L的锁定“
    2018-12-31
    1
  • 骏Jero
    为什么这里使用for mailbox == 1 { }, 看wait内部实现,等待是wait中runtime_notifyListWait(&c.notify, t)起到的作用,感觉用if一样达到效果
    2018-10-12
    1
  • qiushye
    文章的例子是“我发信,你收信”,示例图表达的是“你发信,我收信”,稍有不足.

    作者回复: 你说的是 recvCond?这可不是收信的意思啊。

    2019-08-22
  • bluuus
    我试了一下demo61.go, 发现永远只有一个协程可以进到wait方法,当mailbox初始值是0,只有可能收协程进到wait方法;当mailbox初始值为1,只有可能发协程进到wait方法。为什么会这样

    作者回复: 你对 demo61.go 有改动吗?

    2019-08-14
    1
  • Geek_a8be59
    var mailbox uint8
    var lock sync.RWMutex
    sendCond := sync.NewCond(&lock)
    recvCond := sync.NewCond(&lock)
    为什么不能向上面那样都用同一个互斥量,非要两个不同呢?老师,能讲一下区别么

    作者回复: 如果都用同一个互斥量的话,操作双方就无法独立行事,这就是完全串行的操作了,效率上会大打折扣。

    进一步说,本来就是一个发一个收,理应一个用写锁一个用读锁,这样效率高,之后扩展起来也方便。因为读之间不用互斥。

    2019-08-12
  • demo60太经典了 不仅体会到了锁的用法 还体会到了 如何利用chan 阻塞主线程 以使goroutine完全跑完 算是chan经典用法吧
    2019-07-29
  • ...
    老师 wait会释放锁吗

    作者回复: 每次执行结束前都会释放,要不其他goroutine没法进入锁保护的临界区。

    2019-02-20
    1
  • 打你
    我肯定需要先调用lock变量的Lock方法。注意,这个Loc...

    极客时间版权所有: https://time.geekbang.org/column/article/41588

    这一段写得太拗口啦。什么叫持有锁,而不锁上锁。后面然后又unlock,费解。
    在我看来,这不是读写锁中的写锁么,相当于获取了写锁
    2018-11-10
  • 云学
    本文的例子如果只用一个条件变量,不用2个,是不是也可以呢?
    2018-10-18
  • 卒迹
    if mailbox ==0 {
    recvCond.Wait()
    }
    为什么发送goroutine和发送goroutine用if 替换for打印的结果和用for结构一样的
    2018-10-16
收起评论
15
返回
顶部