双重检查锁定模式 - 在传递给 call_once 的 lambda 中捕获

Posted

技术标签:

【中文标题】双重检查锁定模式 - 在传递给 call_once 的 lambda 中捕获【英文标题】:Double-check lock pattern - capture in lambda passed to call_once 【发布时间】:2018-07-15 07:31:53 【问题描述】:

我正在观看 Herb Sutter 的 CppCon 2014 谈论无锁编程。

在handout page 7,我们有以下代码:

static unique_ptr<widget> widget::instance;
static std::once_flag widget::create;

widget& widget::get_instance() 
    std::call_once( create, [=] instance = make_unique<widget>();  );
    return *instance;

我的问题:为什么这里使用[=] 捕获,而不是[&amp;](或者可能只是[]?)

cppreference 说:

[=] 通过副本捕获 lambda 主体中使用的所有自动变量,如果存在则通过引用捕获当前对象

但我们没有任何自动变量,也不需要当前对象。

【问题讨论】:

我什至会问“而不是[]”。确实看起来很奇怪。 当然,这显然也是非真实代码。下一行的return 无论如何都不会编译。 我认为是错误的,也需要return *instance; @hegel5000:不一定。你可以“蚕食”你的 equals 捕获的局部变量,就像你可以对函数使用按值复制的参数一样(例如,多次推进迭代器)。 我想说的是,这是一个完全未经测试的 sn-p,它只是为了说明一个特定的事情而编写的(call_once 的使用),所以尝试没有多大意义过度解读细节。 【参考方案1】:

这里不需要 capture-default[] 会很好。

正如我在 cmets 中所写,这是一个未经测试的 sn-p,用于说明完全不相关的事物(即 call_once)。尝试过多地阅读它没有多大意义。

也就是说,就“为适合幻灯片而编写的未经测试的 sn-p”类型而言,[=] 可能是最安全的默认lambda-introducer[&amp;] 可能导致数据竞争或悬空引用,如果您需要捕获,[] 将是错误的,并且显式捕获占用幻灯片上的宝贵空间 - 并且需要实际考虑捕获......

【讨论】:

以上是关于双重检查锁定模式 - 在传递给 call_once 的 lambda 中捕获的主要内容,如果未能解决你的问题,请参考以下文章

为啥在双重检查锁定中使用volatile

双重检查锁定和单例模式

双重检查和锁定模式是不是适用于 C++(不是 11)?

单例模式双重检查锁定与延迟初始化你不得不知道的底层原理

单例模式双重检查锁定与延迟初始化你不得不知道的底层原理

双重检查锁定的单例模式和延迟初始化