求求爹给解答下 golang sync.WaitGroup 的疑惑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
main1234
V2EX    Go 编程语言

求求爹给解答下 olang sync.WaitGroup 的疑惑

  •  1
     
  •   main1234 2024-03-26 21:21:04 +08:00 1884 次点击
    这是一个创建于 562 天前的主题,其中的信息可能已经有所发展或是发生改变。

    实在看不懂了,越看越懵,sync.Mutex 无压力看懂,到这个 waitgroup 就跪了,求亲爹指教一下,跪谢

    首先 waitgroup 基本每个版本都有改动,每个改动都逃不开几个话题,内存对齐、原子性

    先看一下 1.17 的结构

    type WaitGroup struct { noCopy noCopy state1 [3]uint32 } func (wg *WaitGroup) state() (statep *uint64, semap *uint32) { if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 { return (*uint64)(unsafe.Pointer(&wg.state1)), &wg.state1[2] } else { return (*uint64)(unsafe.Pointer(&wg.state1[1])), &wg.state1[0] } } 

    再看一下 1.18 的结构

    type WaitGroup struct { noCopy noCopy state1 uint64 state2 uint32 } func (wg *WaitGroup) state() (statep *uint64, semap *uint32) { if unsafe.Alignof(wg.state1) == 8 || uintptr(unsafe.Pointer(&wg.state1))%8 == 0 { // state1 is 64-bit aligned: nothing to do. return &wg.state1, &wg.state2 } else { // state1 is 32-bit aligned but not 64-bit aligned: this means that // (&state1)+4 is 64-bit aligned. state := (*[3]uint32)(unsafe.Pointer(&wg.state1)) return (*uint64)(unsafe.Pointer(&state[1])), &state[0] } } 

    在 32 位系统下,state 函数会走 else ,让 state1[1]和 state1[2]一起变成 uint64 ,这个 uint64 大小为 8 字节 64 位

    waitgroup 废了这么大劲,网上说主要是为了对齐和原子性

    1.我不理解如何保证原子性 使用 state1 字段时候,都用了 atmoic ,我理解 atmoic 已经保证了原子性,莫非是 32 位系统读取 64 位 uint64 时候,这个读操作不是原子性的??如果是这样那么我不理解问题 2

    2.为什么 state 函数在 32 位上的实现可以保证原子性 假如 uint64 占用了 0~31 和 32~63 两个地址位,那么无论怎么对齐,32 位系统怎么能保证一次性、原子性的把这 64 位地址读出来?

    3.为什么 state 函数对 8 取模就能判断是 64 位还是 32 位系统 32 位系统中 WaitGroup 结构体就不能是地址 0x00008 么??这样对 8 取模会判断成是 64 位

    4.为啥不直接使用 uint32 ,解决了对齐和原子性问题

    虚心求教

    6 条回复    2024-03-27 12:13:38 +08:00
    rrfeng
        1
    rrfeng  
       2024-03-26 21:40:17 +08:00 via Android
    32 位需要两个 CPU 指令来操作一个 64 位的值,所以不是原子的。
    我只能回答着一个…
    icgszi
        2
    icgszi  
       2024-03-26 22:02:46 +08:00   1
    1 和 2 是同一个问题,Golang 的 atomic 包要求用户自己保证 64 位对齐,具体可以看官方文档
    https://pkg.go.dev/sync/atomic#pkg-note-BUG
    至于为什么 32 位对齐不行 64 位就可以,只能说是系统提供的 atomic 原语本身决定的。
    3 我觉得你是想复杂了,作者的目的不是判断系统是 32 位还是 64 位,他只是想保证从一段连续的 96 位取出来当作
    statep 的那 64 位是对齐的就好了。比如说如果是 [0, 96),那就取 [0, 64) 作为 statep ,这一段不管是在 32 位系统还是 64 位系统,都是 64 位对齐的,如果是 [32, 128),那就取 [64, 128) 作为 statep ,理由一样。
    4 的话很简单,因为 uint32 不够用。statep 本身就包含了两个 counter ,每个 counter 在 uint32 的范围。atomic 操作 statep 其实是 atomic 操作这两个 counter 。你如果用 uint32 ,那每个 counter 就只有 uint16 的范围了,65536 很容易就超了不满足设计需求。
    icgszi
        3
    icgszi  
       2024-03-26 22:08:23 +08:00
    另外针对 1 2 再补充一句,不必太纠结为什么 32 位对齐不行 64 位对齐就可以,把它当成一个既定特性就好。系统给 Golang 提供的 API 就是这样,Golang 的 atomic 包只是对系统 API 的一系列简单封装,自然也没法儿绕过这个特性。至于各种 32 位系统为什么将 API 设计成这样(原子操作 64 位一定要 64 位对齐),那就得去看设计者的考虑和取舍了。
    doraemonki
        4
    doraemonki  
       2024-03-26 22:21:56 +08:00 via Android
    求教怎么样才能无压力看懂 sync.Mutex
    main1234
        6
    main1234  
    OP
       2024-03-27 12:13:38 +08:00
    @icgszi 谢谢您了,懂了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1152 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 23:28 PVG 07:28 LAX 16:28 JFK 19:28
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86