我有一个线程管道和过滤器实现,我想在我的一个过滤器中使用线程局部副本。我自己没有实现运行循环。相反,只要获得要处理的数据,基类Filter类就会在每个过滤器上调用process()方法。
在这种情况下,我有两个使用thread_locals的问题: 1)我不能在process()方法中声明thread_locals,因为无论何时调用process()方法都要重用线程本地。
以下示例代码:
<keyword>
所以上面我初始化了SomeClass的thread_local实例。但是我没有释放它,因为每当新数据到达时,process()将由同一个线程的运行循环调用。显然,它永远不会被释放。坏。
2)我已经将一个threadCleanup()方法添加到过滤器实现中,只要过滤器停止(并且它的线程停止),现在就会调用它。虽然这需要声明thread_local成员变量,如:
void process(SomeInput in) {
thread_local SomeClass* someClass = nullptr;
if (someClass == nullptr) someClass = new SomeClass(params);
// do stuff here...
}
但这不适用于类和抛出: “thread_local仅允许在变量声明”
在这种情况下声明,分配和取消分配线程局部的正确方法是什么?
答案 0 :(得分:3)
回答原始问题的修复,而不是您为自己创建的新问题:
只需使用原始代码std::unique_ptr
即可。您甚至可以对其进行单行since thread_local
implies static
,因此只需初始化一次,而无需执行nullptr
的每次通话测试:
void process(SomeInput in) {
thread_local std::unique_ptr<SomeClass> someClass(new SomeClass(params));
// do stuff here...
}
任何给定线程第一次调用process
时,为该线程初始化unique_ptr
;当该线程退出时,unique_ptr
被销毁并收集该线程的SomeClass
实例because thread_local
destructors are called on thread exit。
请注意,如果someClass
很小,您可以将其直接存储在thread_local
存储中,而不是将unique_ptr
存储在指向堆的位置,这样可以避免{{1}完全,因为如上所述,unique_ptr
暗示thread_local
并在线程退出时调用析构函数:
static
使用void process(SomeInput in) {
thread_local SomeClass someClass(params);
// do stuff here,
// using someClass. instead of someClass-> for member/method access,
// and &someClass where you used to use someClass if something needs a raw
// pointer (the raw pointer is definitely sticking around until thread
// exit after all)
}
方法可能仍然有利(线程本地存储可能有限/慢,因此将其余类存储在普通堆内存中可能是值得的。)
答案 1 :(得分:2)
您要查找的成员变量static thread_local
的语法是:
class SomeFilter : public Filter <...> {
// ...
private:
static thread_local SomeClass* _someClass;
}
而不是执行手动清理,最好将_someClass
封装在unique_ptr
中,因为线程本地在线程退出时被销毁:
static thread_local std::unique_ptr<SomeClass> _someClass;