C++ Weekly - Episode 61 脱水版: Storage Duration with Lambdas
本集主要讲解 Lambda 表达式的存储周期.
给定一个 lambda 表达式, 主程序将返回 2
, 该变量将会被共享. lambda 表达式具有状态.
int main()
{
auto l = [val = 0] () mutable { return val++; };
l();
l();
return l(); // 2
}
类似等同于包含了一个局部 static
变量, 如下 l2
程序. 当然, 假如对该 lambda 进行赋值, 这个变量也还是被共享的. 这样的 lambda 不是线程安全的.
int main()
{
auto l = [] () {
static auto val = 0;
return val++;
};
auto l2 = l;
l2();
l2();
l();
l();
return l(); // 4
}
比如这样来验证, 通过 std::async
来调用该 lambda, (std::launch::async
参数强制开启单独线程执行 lambda. 如下. 如果调用 f.get()
, 阻塞等待 std::async
返回, 这时候期望返回结果应该是 5
.
若不等待异步返回结果, (注释 f.get()
), 这个时候 lambda 中的静态变量 val 将会陷入竞争状态, 该程序的返回结果变成了 4
.
int main()
{
auto l = [] () {
static auto val = 0;
return val++;
};
auto l2 = l;
auto f = std::async(std::launch::async, l);
// f.get();
l2();
l2();
l();
l();
return l();
}
那么, 我们如何处理解决这类共享的状态变量但又期望线程安全的状态 lambda 函数呢? 通过在函数内部使用 thread_local
线程变量. 这个时候, 无论是否阻塞异步线程调用, 结果都为 4
.
int main()
{
auto l = [] () {
thread_local auto val = 0;
return val++;
};
auto l2 = l;
auto f = std::async(std::launch::async, l);
f.get();
l2();
l2();
l();
l();
return l();
}