V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
yujianwjj
V2EX  ›  Go 编程语言

go 标准库 log 的一个源码疑问

  •  
  •   yujianwjj · 2023-02-08 16:36:59 +08:00 · 2388 次点击
    这是一个创建于 647 天前的主题,其中的信息可能已经有所发展或是发生改变。
    func (l *Logger) SetOutput(w io.Writer) {
    	l.mu.Lock()
    	defer l.mu.Unlock()
    	l.out = w
    	isDiscard := int32(0)
    	if w == io.Discard {
    		isDiscard = 1
    	}
    	atomic.StoreInt32(&l.isDiscard, isDiscard)
    }
    

    上面这段代码用了 atomic.StoreInt32 的意义在哪里?

    func (l *Logger) SetOutput(w io.Writer) {
    	l.mu.Lock()
    	defer l.mu.Unlock()
    	l.out = w
    
    	if w == io.Discard {
    		l.isDiscard = 1
    	}
    }
    

    跟这样写有啥区别?

    15 条回复    2023-02-14 16:00:26 +08:00
    GopherDaily
        1
    GopherDaily  
       2023-02-08 16:39:33 +08:00   ❤️ 3
    In the terminology of the Go memory model, if the effect of an atomic operation A is observed by atomic operation B, then A “synchronizes before” B. Additionally, all the atomic operations executed in a program behave as though executed in some sequentially consistent order. This definition provides the same semantics as C++'s sequentially consistent atomics and Java's volatile variables.

    搜一下 Memory Model
    bolide2005
        2
    bolide2005  
       2023-02-08 16:42:47 +08:00   ❤️ 1
    emmm ,我觉得是,想象一个极端场景,16 位机器存储一个 32 位的数字,那么就会需要至少两条 CPU 指令,分别写高位和低位,这样就存在脏读的可能性
    bolide2005
        3
    bolide2005  
       2023-02-08 16:43:27 +08:00
    所以需要一个原子操作来防止这种情况
    bolide2005
        4
    bolide2005  
       2023-02-08 16:52:31 +08:00
    @GopherDaily #1 学习了
    lolizeppelin
        5
    lolizeppelin  
       2023-02-08 18:09:45 +08:00
    因为有好几个地方无锁读取 isDiscard

    所以都使用 atomic 来无锁化读写 isDiscard
    010203kk
        6
    010203kk  
       2023-02-08 20:06:44 +08:00
    都是高手啊。
    gamexg
        7
    gamexg  
       2023-02-08 21:27:46 +08:00
    我写过类似的代码,锁内部还是用原子操作。
    原因是,其他地方不想加锁,而只是使用原子操作。
    littlewing
        8
    littlewing  
       2023-02-08 21:37:15 +08:00
    按理说所有读取和写入都加锁的话,没必要用 atomic
    GopherDaily
        9
    GopherDaily  
       2023-02-08 21:39:39 +08:00
    @bolide2005 Java 的 Memory Model 网上资料多一点,原理和要做的事都一样的
    wangritian
        10
    wangritian  
       2023-02-08 23:43:14 +08:00
    除了#2 所说 16 位机器问题,atomic 还确保了 l.isDiscard=0/1 一定在 l.out = w 之后,不会乱序执行,进而确保无锁使用 l.isDiscard 时它的结果一定符合 w == io.Discard ,推荐按#1 所说 Memory Model 完整了解一下
    lasuar
        11
    lasuar  
       2023-02-09 00:33:52 +08:00
    答案应该是 5 楼吧。
    yulon
        12
    yulon  
       2023-02-09 02:37:24 +08:00
    无锁读取,有锁修改,比读写锁竞争少
    Rehtt
        13
    Rehtt  
       2023-02-09 08:40:55 +08:00
    应该在其他地方 l.isDiscard 被并发无锁读写,所以用了原子操作
    malaohu
        14
    malaohu  
       2023-02-09 09:36:44 +08:00
    我问了一下 OpenAI GPT-3 答案差不多

    https://jike.info/topic/14265/
    macscsbf
        15
    macscsbf  
       2023-02-14 16:00:26 +08:00
    @wangritian 我不太懂,加了锁的话不是就保证了内存的顺序,保证 l.isDiscard=0/1 一定在 l.out = w 之后, atomic 应该只是因为其他地方存在无锁读取吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2849 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 13:00 · PVG 21:00 · LAX 05:00 · JFK 08:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.