Go语言核心36讲
郝林
《Go并发编程实战》作者,前轻松筹大数据负责人
立即订阅
24108 人已学习
课程目录
已完结 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讲
登录|注册

29 | 原子操作(上)

郝林 2018-10-17
我们在前两篇文章中讨论了互斥锁、读写锁以及基于它们的条件变量,先来总结一下。
互斥锁是一个很有用的同步工具,它可以保证每一时刻进入临界区的 goroutine 只有一个。读写锁对共享资源的写操作和读操作则区别看待,并消除了读操作之间的互斥。
条件变量主要是用于协调想要访问共享资源的那些线程。当共享资源的状态发生变化时,它可以被用来通知被互斥锁阻塞的线程,它既可以基于互斥锁,也可以基于读写锁。当然了,读写锁也是一种互斥锁,前者是对后者的扩展。
通过对互斥锁的合理使用,我们可以使一个 goroutine 在执行临界区中的代码时,不被其他的 goroutine 打扰。不过,虽然不会被打扰,但是它仍然可能会被中断(interruption)。

前导内容:原子性执行与原子操作

我们已经知道,对于一个 Go 程序来说,Go 语言运行时系统中的调度器会恰当地安排其中所有的 goroutine 的运行。不过,在同一时刻,只可能有少数的 goroutine 真正地处于运行状态,并且这个数量只会与 M 的数量一致,而不会随着 G 的增多而增长。
所以,为了公平起见,调度器总是会频繁地换上或换下这些 goroutine。换上的意思是,让一个 goroutine 由非运行状态转为运行状态,并促使其中的代码在某个 CPU 核心上执行。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Go语言核心36讲》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(7)

  • 兔子先生
    "不过,在同一时刻,只可能有少数的 goroutine 真正地处于运行状态,并且这个数量只会与 M 的数量一致,而不会随着 G 的增多而增长。" 个人感觉同时运行的g应该是和p数量相等

    作者回复: 不一定,P 把 G 交给 M 就不管了,调度器发现还有 M 闲着就会继续从那些 P 那边拿 G。

    2019-09-25
  • benying
    打卡
    2019-06-12
  • sureingo
    老师您好,文章中提到互斥锁不能保证临界区内代码的原子性,我用github中demo60做了好多次试验,每次的结果都是正确的,能帮忙解释下吗

    type counter struct {
    num uint // 计数。
    mu sync.RWMutex // 读写锁。
    }

    // number 会返回当前的计数。
    func (c *counter) number() uint {
    c.mu.RLock()
    defer c.mu.RUnlock()
    return c.num
    }

    // add 会增加计数器的值,并会返回增加后的计数。
    func (c *counter) add(increment uint) uint {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.num += increment
    return c.num
    }

    func main() {
    c := counter{}
    sign := make(chan struct{})
    for i := 0; i < 1000; i++ {
    go func() {
    defer func() {
    sign <- struct{}{}
    }()
    for j := 0; j < 1000; j++ {
    c.add(1)
    }
    }()
    }
    for i := 0; i < 1000; i++ {
    <-sign
    }
    fmt.Println(c.number())
    }
    输出是1000000
    2018-11-29
    1
  • 翅膀
    绕过需要一个中间变量
    2018-11-15
  • 任小样🏂
    楼上的,认真审题,可以绕过。但我的问题来了,这算BUG嘛?
    2018-11-08
  • MagicYang
    uint32(int32(-3)) 貌似绕不过
    2018-11-04
  • Askerlve
    go入门菜鸟,感激有这么一个专栏,学完就可以买一本go并发编程来撸了~😀
    2018-10-17
收起评论
7
返回
顶部