为什么atomic.StoreUint32比sync.Once中的普通分配更受欢迎?

2023-11-23

在阅读Go源码时,我对src/sync/once.go中的代码有一个疑问:

func (o *Once) Do(f func()) {
    // Note: Here is an incorrect implementation of Do:
    //
    //  if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
    //      f()
    //  }
    //
    // Do guarantees that when it returns, f has finished.
    // This implementation would not implement that guarantee:
    // given two simultaneous calls, the winner of the cas would
    // call f, and the second would return immediately, without
    // waiting for the first's call to f to complete.
    // This is why the slow path falls back to a mutex, and why
    // the atomic.StoreUint32 must be delayed until after f returns.

    if atomic.LoadUint32(&o.done) == 0 {
        // Outlined slow-path to allow inlining of the fast-path.
        o.doSlow(f)
    }
}

func (o *Once) doSlow(f func()) {
    o.m.Lock()
    defer o.m.Unlock()
    if o.done == 0 {
        defer atomic.StoreUint32(&o.done, 1)
        f()
    }
}

Why is atomic.StoreUint32使用,而不是说o.done = 1?这些不是等价的吗?有什么区别?

我们必须使用原子操作(atomic.StoreUint32)以确保其他 goroutine 可以观察到效果f() before o.done在内存较弱的机器上设置为 1 吗?


请记住,除非您手动编写程序集,否则您不是针对机器的内存模型进行编程,而是针对 Go 的内存模型进行编程。这意味着即使原始分配对于您的架构来说是原子的,Go 也需要使用原子包来确保所有支持的架构的正确性。

访问done互斥体之外的flag只需要安全,不需要严格排序,因此可以使用原子操作而不是总是用互斥体获取锁。这是一种使快速路径尽可能高效的优化,允许sync.Once用于热路径。

互斥锁用于doSlow仅用于该函数内的互斥,以确保只有一个调用者能够实现f()之前done标志已设置。该标志是使用atomic.StoreUint32,因为它可能同时发生atomic.LoadUint32位于受互斥锁保护的临界区之外。

正在阅读done字段与写入(甚至原子写入)同时进行,是一种数据竞争。仅仅因为该字段是原子读取的,并不意味着您可以使用正常的赋值来写入它,因此首先检查该标志atomic.LoadUint32并写有atomic.StoreUint32

直接读取的done within doSlow is安全,因为它受到互斥锁的并发写入保护。同时读取值atomic.LoadUint32是安全的,因为两者都是读操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么atomic.StoreUint32比sync.Once中的普通分配更受欢迎? 的相关文章

随机推荐

  • 如何制作只有 2 列的 Discord 嵌入

    我正在尝试制作一个只有 2 列的嵌入 每当我删除内联值时 它都会像我想要的那样删除 test3 字段 然后我在 test4 字段上保持 inline true 它会下降到另一行 我尝试将 test3 和 test4 内联值设置为 false
  • Rikulo dart 到底是什么?

    我一直在阅读网站上的摘要http www rikulo org但所有这些神秘含糊的陈述对我没有帮助 这些例子都是关于视觉效果的 我不明白这个框架能够做什么 缺少大图景 我可以使用 rikulo 构建哪些类型的应用程序 是否可以访问硬件 可以
  • Spring Cloud Config 自定义环境存储库

    我想知道是否有一个示例如何为 Spring Cloud Config 创建自定义环境存储库 因为有 git svn vault 存储库 但我不想使用它们 我需要自定义一个 例如 如果我只想将所有属性存储在地图中 在应用程序上下文中以 bea
  • R,将变量传递给系统命令

    我希望使用 R 创建一个 QR 代码并将其嵌入到 Excel 电子表格 数百个代码和电子表格 中 显而易见的方法似乎是使用命令行创建二维码 并在 R 中使用 system 命令 有谁知道如何通过 system 命令传递 R 变量 谷歌不太有
  • 有没有办法使用 pandas.ExcelWriter 自动调整 Excel 列宽?

    我被要求生成一些 Excel 报告 我目前在数据中大量使用 pandas 所以我自然想使用pandas ExcelWriter生成这些报告的方法 然而 固定的列宽是一个问题 到目前为止我的代码很简单 假设我有一个名为的数据框df write
  • 生成 v5 UUID。什么是名称和命名空间?

    我读过man页面 但我不明白什么name and namespace是给 对于版本 3 和版本 5 UUID 附加命令行 必须给出参数名称空间和名称 命名空间是 字符串表示形式的 UUID 或 内部预定义命名空间 UUID 的标识符 当前已
  • R:使用 system() 调用的别名命令

    In my bash profile文件我把这个alias命令 which mvsync alias mvsync rsync remove source files arvuP usr bin rsync 它在 bash shell 中工
  • 如何在 Rails3 和 Devise 注册后添加回调

    如何添加回调来为注册用户创建帐户 设计文件 registrations controller rb 位于controllers devise下 我的用户模型具有 has many accounts 关系 并且帐户模型具有 own to us
  • R 中的 REGEX:从字符串中提取单词

    我想这是一个常见的问题 我发现了很多网页 包括一些来自SO的网页 但我无法理解如何实现它 我是 REGEX 新手 我想在 R 中使用它来提取句子中的前几个单词 例如 如果我的句子是 z I love stack overflow it is
  • 使用 DownloadManager 在活动内显示下载进度

    我试图重现 DownloadManager 在我的应用程序内的通知栏中显示的相同进度 但我的进度从未发布 我正在尝试使用 runOnUiThread 更新它 但由于某种原因它没有更新 我的下载 String urlDownload http
  • UITableview 附件类型在滚动时消失

    我制作了一个 tableView 我需要在其中选择多个选项 选项已选择 但当我滚动表视图时 复选标记选项消失 其他一些行显示该复选标记 这是我的代码didselectedrowAtindex method table option is U
  • Chrome中textarea的默认字体样式是什么? (文本输入与文本区域的文本“大小”)

    Chrome中textarea的默认字体样式是什么 使它默认的样子应该是什么样的 我的问题的目的是我想让输入中的文本与文本区域中的文本相同 在文本输入中可能太 粗体 P问题应该是 文本区域应用的默认字体属性是什么 如果我想看起来像默认的那样
  • 如何打开内存中存储的 PDF

    我有一个应用程序 可以下载 PDF 文件并将其以 MODE PRIVATE 出于安全目的 存储在应用程序的内部存储器上 FileOutputStream fos getApplicationContext openFileOutput LO
  • 将自定义命令行参数传递给 Rust 测试

    我有一个 Rust 测试 它委托给 C 测试套件使用doctest并希望将命令行参数传递给它 我的第一次尝试是 in mod ffi pub fn run tests cli args mut String gt bool test fn
  • AutoMockContainer 支持具有非接口依赖项的自动模拟类

    我有一个具有非接口依赖性的构造函数 public MainWindowViewModel IWorkItemProvider workItemProvider WeekNavigatorViewModel weekNavigator 我正在
  • 如何更改禁用控件的样式?

    当 WinForm 元素被禁用时 它会变灰 是否可以禁用某个元素 但调整禁用的样式 使其看起来仍然启用 而不是灰显 防止可聚焦控件夺取焦点需要采取多种对策 您必须包含一个控件does此类的重点是抵制所有尝试 using System usi
  • python进程池,每个进程都有超时,而不是池中的所有进程

    我需要运行许多进程 但不是全部运行 例如同时运行 4 个进程 multiprocessing Pool正是我所需要的 但问题是 如果进程持续超过超时 例如 3 秒 我需要终止该进程 Pool仅支持等待所有进程的超时 而不是每个进程的超时 这
  • Acer Iconia A500 不在 adb 设备中

    刚刚拿起一台 Iconia A500 是的 优惠券优惠 100 美元 并开始玩游戏等 我决定终于到了工作的时候了 启动了 adb 并启动了 eclipse 来测试一个应用程序 我发现它不在我的设备列表中 我已经尝试安装 acer 驱动程序
  • 更改 ggplot2 中图例键中的符号

    此 R 代码生成一个 ggplot2 图表 其中图例键包含以红色 蓝色和绿色重复的字母 a x lt rnorm 9 y lt rnorm 9 s lt rep c F G K each 3 df lt data frame x y s r
  • 为什么atomic.StoreUint32比sync.Once中的普通分配更受欢迎?

    在阅读Go源码时 我对src sync once go中的代码有一个疑问 func o Once Do f func Note Here is an incorrect implementation of Do if atomic Comp