std::call_once 与 std::mutex 的线程安全初始化

2024-01-05

我对目的有点困惑std::call_once。明确地说,我确切地理解什么std::call_once does,以及如何使用它。它通常用于原子地初始化某种状态,并确保只有一个线程初始化该状态。我还在网上看到了许多尝试创建线程安全的单例std::call_once.

As 在这里展示 http://www.nuonsoft.com/blog/2012/10/21/implementing-a-thread-safe-singleton-with-c11/comment-page-1/,假设您编写了一个线程安全的单例,如下所示:

CSingleton& CSingleton::GetInstance()
{
    std::call_once(m_onceFlag, [] {
        m_instance.reset(new CSingleton);
    });
    return *m_instance.get();
}

好吧,我明白了。但我以为唯一的事情std::call_once真正保证的是传递的函数将only被执行一次。但有吗also保证如果多个线程之间存在调用该函数的竞争,并且一个线程获胜,则其他线程将获胜block直到获胜线程从调用返回?

因为如果是这样,我认为两者之间没有区别call_once和一个普通的同步互斥体,例如:

CSingleton& CSingleton::GetInstance()
{
    std::unique_lock<std::mutex> lock(m_mutex);
    if (!m_instance)
    {
      m_instance.reset(new CSingleton);
    }
    lock.unlock();

    return *m_instance;
}

So, if std::call_once确实强制其他线程阻塞,那么有什么好处呢std::call_once提供常规互斥锁吗?再想一想,std::call_once肯定会have强制其他线程阻塞,或者用户提供的函数中完成的任何计算都不会同步。再说一遍,什么是std::call_once提供高于普通互斥锁的价格吗?


一件事是call_once为你做的是处理异常。也就是说,如果第一个线程在函子内部抛出异常(并将其传播出去),call_once不会考虑call_once使满意。允许后续调用再次进入函子,以努力完成它而不会出现异常。

在你的例子中,异常情况也得到了正确的处理。然而,很容易想象一个更复杂的函子,其中特殊情况将无法得到正确处理。

话虽这么说,我注意到call_once与 function-local-statics 是多余的。例如。:

CSingleton& CSingleton::GetInstance()
{
    static std::unique_ptr<CSingleton> m_instance(new CSingleton);
    return *m_instance;
}

或者更简单地说:

CSingleton& CSingleton::GetInstance()
{
    static CSingleton m_instance;
    return m_instance;
}

上面相当于你的例子call_once,恕我直言,更简单。哦,除了这个和你的例子之间的破坏顺序有非常微妙的不同。在这两种情况下m_instance以与构建相反的顺序被破坏。但构建顺序不同。在你的m_instance是相对于同一翻译单元中具有文件本地范围的其他对象构造的。使用函数局部静态,m_instance是第一次构建GetInstance被执行。

这种差异对于您的申请可能很重要,也可能不重要。一般来说,我更喜欢函数局部静态解决方案,因为它是“惰性的”。 IE。如果应用程序从不调用GetInstance() then m_instance从未被建造过。在应用程序启动期间,没有任何时期会尝试立即构建大量静态数据。您只需在实际使用时支付施工费用。

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

std::call_once 与 std::mutex 的线程安全初始化 的相关文章

  • C#.Net 邮件将进入垃圾邮件文件夹

    我正在从 ASP net Web 应用程序发送电子邮件 邮件发送成功 没有失败 但大多数都进入了垃圾邮件文件夹 请帮助我克服垃圾邮件过滤器 我的发送邮件代码 public void SendMail string FromAddress s
  • 如何使用 openSSL 函数验证 PEM 证书的密钥长度

    如何验证以这种方式生成的 PEM 证书的密钥长度 openssl genrsa des3 out server key 1024 openssl req new key server key out server csr cp server
  • 在 C++ 代码中转换字符串

    我正在学习 C 并开发一个项目来练习 但现在我想在代码中转换一个变量 字符串 就像这样 用户有一个包含 C 代码的文件 但我希望我的程序读取该文件并插入将其写入代码中 如下所示 include
  • 如何在 C# 中将 Json 转换为对象

    我想将 Json 转换为 C 中的对象 这里的 Json 是 值 e920ce0f e3f5 4c6f 8e3d d2fbc51990e4 如何使用 Object 问题看似愚蠢 但其实并不那么愚蠢 我没有简单的 Json 我有 IEnume
  • 2个对象,完全相同(除了命名空间)c#

    我正在使用第三方的一组网络服务 但遇到了一个小障碍 在我手动创建将每个属性从源复制到目标的方法之前 我想我应该在这里寻求更好的解决方案 我有 2 个对象 一个是 Customer CustomerParty 类型 另一个是 Appointm
  • 防止控制台应用程序中的内存工作集最小化?

    我想防止控制台应用程序中的内存工作集最小化 在Windows应用程序中 我可以这样做覆盖 SC MINIMIZE 消息 http support microsoft com kb 293215 en us fr 1 但是 如何在控制台应用程
  • MVC 5 中具有 ASP.NET Identity 的 Autofac 不会验证 OWIN 管道中的安全标记

    我在 MVC 5 中设置了 AutoFac 来与 ASP NET Identity 一起使用 表面上一切似乎都工作正常 即用户可以创建帐户并登录 但后来我发现 当安全标记更改时 用户不会注销 通过在 AspNetUsers 表中进行暴力破解
  • 条件类型定义

    如果我有一小段这样的代码 template
  • 如何在 Javascript 中连接 C# ActiveX 事件处理程序

    我尝试使用几个代码片段将 ActiveX 对象与 Javascript 事件处理程序挂钩 我无法确定为什么事件处理程序没有被调用 带有项目的 Github 存储库 https github com JesseKPhillips Csharp
  • Unity c# 四元数:将 y 轴与 z 轴交换

    我需要旋转一个对象以相对于现实世界进行精确旋转 因此调用Input gyro attitude返回表示设备位置的四元数 另一方面 这迫使我根据这个四元数作为默认旋转来计算每个旋转 将某些对象设置为朝上的简单方法如下 Vector3 up I
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • .NET 和 Mono 之间的开发差异

    我正在研究 Mono 和 NET C 将来当项目开发时我们需要在 Linux 服务器上运行代码 此时我一直在研究 ASP NET MVC 和 Mono 我运行 Ubuntu 发行版 想要开发 Web 应用程序 其他一些开发人员使用 Wind
  • 以编程方式创建 Blob 存储容器

    我有一个要求 即在创建公司时 在我的 storageaccount 中创建关联的 blob 存储容器 并将容器名称设置为传入的字符串变量 我已尝试以下操作 public void AddCompanyStorage string subDo
  • 如何编写一个接受 int 或 float 的 C 函数?

    我想用 C 语言创建一个扩展 Python 的函数 该函数可以接受 float 或 int 类型的输入 所以基本上 我想要f 5 and f 5 5 成为可接受的输入 我认为我不能使用if PyArg ParseTuple args i v
  • 如何获取带有某个属性注释的所有属性?

    我刚刚从 Roslyn 开始 我想找到所有用属性名称 OneToOne 注释的属性 我启动了 SyntaxVisualizer 并能够获取对该节点的引用 但我想知道是否有更简单的方法来实现此目的 这就是我所拥有的 var prop docu
  • 任何人都可以清楚地告诉如何在不使用像 这样的预定义函数的情况下找到带有小数值或小数值的指数吗? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 例如 2 0 5 1 414 所以想要 我是 c 的新手 所以请解释简单的逻辑 如果不是复杂的逻辑也足够了 在数学中 从整数取幂到实数
  • GCD 与自定义队列

    我想知道这两者的性能有什么区别 dispatch async dispatch get global queue DISPATCH QUEUE PRIORITY HIGH 0 perform complex operation dispat
  • 如何组合两个 lambda [重复]

    这个问题在这里已经有答案了 可能的重复 在 C 中组合两个 lambda 表达式 https stackoverflow com questions 1717444 combining two lamba expressions in c
  • 如何为有时异步的操作创建和实现接口

    假设我有数百个类 它们使用 计算 方法实现公共接口 一些类将执行异步 例如读取文件 而实现相同接口的其他类将执行同步代码 例如将两个数字相加 为了维护和性能 对此进行编码的好方法是什么 到目前为止我读到的帖子总是建议将异步 等待方法冒泡给调
  • 如何在 ASP.NET Core 中注入泛型的依赖关系

    我有以下存储库类 public class TestRepository Repository

随机推荐