提问人:user2296145 提问时间:6/11/2023 最后编辑:user2296145 更新时间:6/12/2023 访问量:67
初始化 lambda 中不使用该成员的静态thread_local成员
Initialization of static thread_local member inside lambda that does not use that member
问:
我有类似于以下内容的代码(此代码不编译,仅用于说明目的):
class A {
std::mutex m_;
std::vector<B*> bv_;
struct B {
B() {
std::lock_guard _(m);
bv_.push_back(this);
}
template<typename Lambda>
void push(Lambda&& lambda) {
// saves lambda in a queue
}
void work() {
// executes the lambdas from the queue
}
};
static thread_local B local_;
public:
void push() {
local_.push([] () {
// lambda that does things
}
}
void poll() {
std::lock_guard _(m);
for (auto * b : bv_) {
b->work();
}
}
};
我们有一个 B 类型的static_thread本地成员local_,它内部有一个 lambda 队列,在调用 A::p ush 时推送。创建 B 时,它会将自身添加到 A 中的队列中。A::p oll 遍历此队列,并调用 B::work,后者运行之前推送的 lambda。我们可以从不同的线程调用 A::p ush 和 A::p oll。
我所看到的是,当从与最初调用 A::p ush 的线程不同的线程调用 A::p oll 时,此代码会死锁。原因是,对于调用 A::p oll 的线程,local_ 在执行推送到队列的 lambda 时正在初始化。就上下文而言,从未从调用 A::p oll 的线程调用 A::p ush。在这种情况下,lambda 的作用无关紧要,因为 lambda 对 local_ 不执行任何操作。
我在 cpp 规范中发现了一些可以解释正在发生的事情的东西:
“具有线程存储持续时间的变量应在 其首次使用ODR(6.2),如果建成,应在 线程退出。
我的问题是:为什么在运行 lambda 时会初始化local_?local_在执行 lambda 时是否被初始化,因为这是 local_ 的第一次 odr 使用(即使 local_ 真的没有在那里使用,我想 odr 使用中“使用”的定义可能不是人们直观地认为的那样)?
将其添加为 A::p oll 中的第一行:
(void)local_;
解决了该问题。
谢谢。
编辑:试图使问题更清晰:在此代码中:
void push() {
local_.push([] () {
// lambda that does things, none of them have anything to do with local_
}
}
编译器在 Lambda 中添加了对 for 的调用,问题是,如果 Lambda 内部未使用(甚至不可见)local_编译器为什么要这样做。__tls_init
local_
答:
从伪代码来看,您似乎正在尝试复制线程池?如果是这样,为什么不使用条件变量实现线程池呢?
评论