线程局部变量的初始化
Initialization of thread-local variables
我最近使用了一个对象,其目的是作为单例分配和释放内存。像
class MyValue
{
// ...
static Allocator& GetAllocator()
{
static Allocator allocator;
return allocator;
}
// ...
};
我后来意识到 Allocator
不是线程安全的:当多个线程同时使用同一个分配器时,偶尔会发生奇怪的事情,导致断言和分段错误。
解决方案:对不同的线程使用不同的分配器:
class MyValue
{
// ...
static Allocator& GetAllocator()
{
thread_local static Allocator allocator;
return allocator;
}
// ...
};
太棒了!我的问题消失了!只有一个问题:
是否会在每次创建线程时都初始化我的分配器变量,即使大多数线程不会使用该变量?
分配器的初始化可能是繁重的操作,所以我希望它只在实际需要时才初始化,而不是在每个线程中初始化。
我读到 thread_local
变量由每个线程分配。这是否意味着它们也是 构造的 ?这种分配(或构造)是针对创建的每个线程还是仅针对使用它的线程系统地发生?
我依稀记得在一门课程中听说过有关线程和线程本地存储的大部分细节都取决于平台。如果是这样的话,我对 Linux 和 FreeBSD 特别感兴趣。
相关(有趣的读物,但我在那里找不到答案):
What does the thread_local mean in C++11?
What is the performance penalty of C++11 thread_local variables in GCC 4.8?
我可以给你一个解决方案,检查它是否在你每次调用GetAllocator()
时创建了一个Allocator
类型的新对象。只需调用此方法至少 5 次并检查所有对象的地址 return。如果所有 return 对象的地址都不同,那么它会在每次调用中创建不同的对象,或者如果不是,它只是 return 每次调用时相同对象的地址 GetAllocator()
.
[basic.stc.thread] 状态
All variables declared with the thread_local
keyword have thread storage duration. The storage for these entities shall last for the duration of the thread in which they are created. There is a distinct object or reference per thread, and use of the declared name refers to the entity associated with the current thread.
A variable with thread storage duration shall be initialized before its first odr-use (6.2) and, if constructed, shall be destroyed on thread exit.
因此,您将在每个线程中获得对象的存储空间。我们还有 [stmt.dcl]/4 表示
Dynamic initialization of a block-scope variable with static storage duration (6.7.1) or thread storage duration (6.7.2) is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization.
所以,如果我们到达声明,那么对象将被初始化,如果它有一个构造函数,它将被调用。
如果我们将所有这些放在一起,您将有许多构造函数和析构函数调用等于实际达到的线程数
thread_local static Allocator allocator;
我最近使用了一个对象,其目的是作为单例分配和释放内存。像
class MyValue
{
// ...
static Allocator& GetAllocator()
{
static Allocator allocator;
return allocator;
}
// ...
};
我后来意识到 Allocator
不是线程安全的:当多个线程同时使用同一个分配器时,偶尔会发生奇怪的事情,导致断言和分段错误。
解决方案:对不同的线程使用不同的分配器:
class MyValue
{
// ...
static Allocator& GetAllocator()
{
thread_local static Allocator allocator;
return allocator;
}
// ...
};
太棒了!我的问题消失了!只有一个问题: 是否会在每次创建线程时都初始化我的分配器变量,即使大多数线程不会使用该变量?
分配器的初始化可能是繁重的操作,所以我希望它只在实际需要时才初始化,而不是在每个线程中初始化。
我读到 thread_local
变量由每个线程分配。这是否意味着它们也是 构造的 ?这种分配(或构造)是针对创建的每个线程还是仅针对使用它的线程系统地发生?
我依稀记得在一门课程中听说过有关线程和线程本地存储的大部分细节都取决于平台。如果是这样的话,我对 Linux 和 FreeBSD 特别感兴趣。
相关(有趣的读物,但我在那里找不到答案):
What does the thread_local mean in C++11?
What is the performance penalty of C++11 thread_local variables in GCC 4.8?
我可以给你一个解决方案,检查它是否在你每次调用GetAllocator()
时创建了一个Allocator
类型的新对象。只需调用此方法至少 5 次并检查所有对象的地址 return。如果所有 return 对象的地址都不同,那么它会在每次调用中创建不同的对象,或者如果不是,它只是 return 每次调用时相同对象的地址 GetAllocator()
.
[basic.stc.thread] 状态
All variables declared with the
thread_local
keyword have thread storage duration. The storage for these entities shall last for the duration of the thread in which they are created. There is a distinct object or reference per thread, and use of the declared name refers to the entity associated with the current thread.A variable with thread storage duration shall be initialized before its first odr-use (6.2) and, if constructed, shall be destroyed on thread exit.
因此,您将在每个线程中获得对象的存储空间。我们还有 [stmt.dcl]/4 表示
Dynamic initialization of a block-scope variable with static storage duration (6.7.1) or thread storage duration (6.7.2) is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization.
所以,如果我们到达声明,那么对象将被初始化,如果它有一个构造函数,它将被调用。
如果我们将所有这些放在一起,您将有许多构造函数和析构函数调用等于实际达到的线程数
thread_local static Allocator allocator;