【问题标题】:Is sync.WaitGroup a "synchronization primitive"?sync.WaitGroup 是“同步原语”吗?
【发布时间】:2017-12-11 21:27:42
【问题描述】:

go memory model 文件说

要序列化访问,请使用通道操作或其他同步原语(例如同步和同步/原子包中的同步原语)保护数据。

sync package

包同步提供基本的同步原语,例如互斥锁

因此我们可以得出结论sync.Mutex 是一个同步原语。还有一个非常强烈的暗示,即该包中的其他类型是同步原语。但是,它并没有明确说明,例如sync.WaitGroup 是。

阅读source of WaitGroup,我无法完全说服自己不会围绕WaitGroup 函数重新安排内存操作(例如,我可以使用java 的synchronized 关键字)。我相信它在之前/之后进行序列化,但我怎么能确定。

sync.WaitGroup 是“同步原语”吗?我不只是在寻找答案“是”(或“否”),而是寻找可以证明这一点的指针。

【问题讨论】:

  • WaitGroup 如果不是同步原语就不会很有用。
  • 它也不在sync 包中。
  • 感谢 cmets。但是,除了“直观”级别之外,它并没有真正回答我的问题。这段代码或保证在WaitGroup 访问之前/之后不会重新排列内存访问的文档是什么?

标签: multithreading go synchronization memory-model


【解决方案1】:

如果你违背了明智的advice 并一直跟随海龟...

wg.Add() 导致第 63 行,这导致atomic.AddUint64() 导致此汇编代码:

LOCK
XADDQ   AX, 0(BP)

另一方面,wg.Wait() 导致第 121 行导致atomic.CompareAndSwapUint64() 导致:

LOCK
CMPXCHGQ    CX, 0(BP)

这显然是您构建WaitGroup 的方式:)。具有锁定原子交换和添加锁定原子比较和交换。对我来说很确定。您无法与汇编程序抗争。好吧,也许你可以我不能。

开启x86 locks

【讨论】:

    【解决方案2】:

    sync.WaitGroup 已同步。如果您阅读源代码,您会看到它使用sync/atomic 来同步计数器上的操作。

    【讨论】:

    • 哪里可以保证编译器不会在WaitGroup函数前后移动内存访问指令?
    • 什么意思? WaitGroup 是内部同步的,这些函数之外的任何代码都是你的责任。
    • golang.org/src/sync/waitgroup.go?s=3482:3518#L111。该包使用原子加载和保存,运行时保证是同步的。如果您调用<waitgroup>.Wait(),之后发生的内存操作不能在原子加载操作之前重新排列(因此在Wait() 调用之前)。
    • golang.org/ref/mem#tmp_2Within a single goroutine, reads and writes must behave as if they executed in the order specified by the program.。这意味着发生在原子读取内存操作之后的内存操作必须总是像它发生在单个goroutine范围内的内存操作之后一样运行(这是Waitgroup或任何同步原语,无论如何都会做)。编译器可以移动操作,但不足以违反该约束。
    • Kaedys 在我搜索规范时击败了我。另请注意 Kaedys 链接的同一页面上的“建议”部分:“如果您必须阅读本文档的其余部分才能了解程序的行为,那么您太聪明了。不要聪明。” syncsync/atomic 软件包按广告宣传的那样工作。如果您可以产生他们没有的场景,请提交错误报告。如果您真的很想了解它的幕后工作原理,请阅读编译器的完整源代码syncsync/atomic
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-28
    • 2015-05-26
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    相关资源
    最近更新 更多