我正在libc为非常小的和静态链接的程序实现一小部分,我认为添加TLS支持将是一个很好的学习体验.我使用Ulrich Drepper的TLS文档作为参考.
我设置了两个字符串来试试这个:
static __thread const char msg1[] = "TLS (1).\n"; /* 10 bytes */
static __thread const char msg2[] = "TLS (2).\n"; /* 10 bytes */
编译器生成以下指令以访问它们:
mov    rbx, QWORD PTR fs:0x0 ; Load TLS.
lea    rsi, [rbx-0x14]       ; Get a pointer to 'msg1'. 20 byte offset.
lea    rsi, [rbx-0xa]        ; Get a pointer to 'msg2'. 10 byte offset.
我们假设我将TCB放在堆栈的某个位置:
struct tcb {
    void* self; /* Points to self. I read that this was necessary …int i;
int main() {
     return i;    
}
-static编译后readelf -l显示 elf 的程序头:
Elf file type is EXEC (Executable file)
Entry point 0xxxxx30
There are 6 program headers, starting at offset 52
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x79868 0x79868 R E 0x1000
 > LOAD           0x079f94 0x080c2f94 0x080c2f94 0x0078c 0x02254 RW  0x1000  <<
  NOTE           0x0000f4 0x080480f4 0x080480f4 0x00020 0x00020 R   0x4
 > TLS            0x079f94 0x080c2f94 0x080c2f94 0x00010 0x0002c R   0x4 …假设有一些使用全局变量的不可重入函数:
int i;
void foo(void){
/* modify i */
}
然后,我想在多线程代码中使用此函数,因此我可以这样更改代码:
void foo(int i){
/* modify i */
}
或者,通过使用gcc __thread说明符,更简单:
__thread int i;
void foo(void){
/* modify i */
}
最后的优点是我不需要更改另一个调用foo()的代码.
我的问题是,线程本地存储的开销是多少?TLS有一些不明显的问题吗?
如果我将通过单独的指针修改TLS`ed变量,是否有一些开销,如下所示:
__thread int i;
void foo(void){
int *p = &i;
/* modify i using p pointer */
}
谢谢.
这是测试代码
#include "windows.h"
#include "iostream"
using namespace std;
__declspec(thread) int tls_int = 0;
void NTAPI tls_callback(PVOID, DWORD dwReason, PVOID)   
{
    tls_int = 1;
}
#pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK p_thread_callback = tls_callback;
#pragma data_seg()
int main()
{
    cout<<"main thread tls value = "<<tls_int<<endl;
    return 0;
}
使用多线程调试DLL(/ MDd)运行结果:主线程tls值= 1
使用多线程调试(/ MTd)运行结果:主线程tls值= 0
看起来无法捕获使用MTd时创建的主线程
为什么?
我使用pthread TLS实现了一种"线程本地单例",我想知道在这种情况下如何(以及何时)我可能删除pthread_key_t,因为现在,TLS键使用的内存永远不会是免费的' d.
这样做的目的是让类A派生自ThreadLocalSingleton <A>,它使A成为一个线程本地单例,假设A只有私有构造函数而ThreadLocalSingleton <A>是A的朋友.
哦,还 - 你认为这个实现有任何问题; 我忽略了什么重要的事吗?
#include <pthread.h>
#include <iostream>
template <class T>
class ThreadLocalSingleton
{
private:
    static pthread_key_t tlsKey;
    static pthread_once_t tlsKey_once;
    static void tls_make_key()
    {
        (void)pthread_key_create(&ThreadLocalSingleton::tlsKey, ThreadLocalSingleton::tls_destructor);
    }
    static void tls_destructor(void* obj)
    {
        delete ((T*)obj);
        pthread_setspecific(tlsKey, NULL); // necessary or it will call the destructor again.
    }
public:
    /*
     * A thread-local singleton getter, the resulted object must never be released,
     * it is auto-released when the thread exits.
     */
    static T* getThreadInstance(void)
    { …这个问题可能看起来很奇怪。我想这样做是因为我们有一些代码需要在多个平台上构建,但有些平台不支持 thread_local,然后使用 boost::thread_specific_ptr 代替。然而,为每个平台(x86/x64/arm、调试/发布、操作系统,太多)构建 boost 二进制文件是令人不快的。
我想知道是否可以通过 thread_local 导入 thread_specific_ptr ,以便我们可以使客户端代码更加优雅(避免#ifdef)
我想要一个头文件,例如:
#if HAS_THREAD_LOCAL
class thread_specific_ptr
{
    ... // use thread_local to implement
};
#else
using boost::thread_specific_ptr
#endif
我找不到路,也许你可以,谢谢。
在 MSDN 中阅读以下页面:
我无法理解在FreeLibrary()调用的情况下谁负责释放每个线程的 TLS 插槽指向的内存。
据我了解,如果我有多个正在运行的线程,它们都会在给定索引中的 TLS 插槽内分配内存。当FreeLibrary()被调用时, onlyDLL_PROCESS_DETACH被触发,因此只有收到DLL_PROCESS_DETACH通知的线程才有机会LocalFree()在调用TlsFree()索引之前调用存储在 TLS 插槽中的自己的数据。这会导致所有没有机会调用LocalFree()其数据的其他线程发生内存泄漏,因为它们没有收到DLL_THREAD_DETACH通知。
有人可以解释应该在何时何地释放存储在每个线程的 TLS 插槽中的缓冲区吗?
thread_local在块范围内使用变量有什么用?
如果一个可编译的示例有助于说明问题,这里是:
#include <thread>
#include <iostream>
namespace My {
    void f(int *const p) {++*p;}
}
int main()
{
    thread_local int n {42};
    std::thread t(My::f, &n);
    t.join();
    std::cout << n << "\n";
    return 0;
}
输出: 43
在示例中,新线程有自己的,n但(据我所知)不能用它做任何有趣的事情,所以为什么要麻烦呢?新线程自己的n有什么用吗?如果它没有用,那又有什么意义呢?
当然,我认为有是一个点。我只是不知道这有什么意义。这就是我问的原因。
如果新线程自己n想要(如我所想)在运行时由 CPU 进行特殊处理——也许是因为,在机器代码级别,人们无法n通过从新线程的基指针的预先计算的偏移量以正常方式访问自己的线程堆栈——那我们岂不是白白浪费机器周期和电力?然而即使不需要特殊处理,仍然没有收获!不是我能看到的。
那么为什么thread_local在块范围内?
参考
thread_local和其他存储类我想知道以下两个声明之间的区别是什么,如果两者都写在一个头文件中:
inline thread_local MyClass obj1;  // inline with thread_local
thread_local MyClass obj2;         // no inline
如 C++17 中所述,向变量添加内联会强制所有翻译单元看到该变量的相同地址。这是否意味着可以obj2在不同的翻译单元中获得不同的地址值?在什么情况下要突出显示我们应该使用obj1而不是obj2?
我已经尝试构建 mingw-w64 工具链好几天了,但我一直在构建交叉编译器 GCC 8.1.0。
问题是我必须启用线程本地存储 (TLS),因此我传递--enable-tls给 GCC 的配置脚本。
没有成功,因为在构建结束时,_GLIBCXX_HAVE_TLS在 中未定义config.h,对于 也是如此_GLIBCXX_HAVE_CC_TLS。
我尝试浏览甚至修补自动工具文件以了解如何使其工作。
有人遇到过这个问题吗?
请注意,Windows 上的 mingw-w64 安装程序具有 TLS 符号,因此必须可以为此目标和 TLS 构建 GCC。